home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / terms / kermit / b / ckmco2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-30  |  97.1 KB  |  3,397 lines

  1. /* $Id: ckmco2.c,v 1.9 91/12/27 21:28:52 fdc Exp $
  2.  * $Source: /uw/mackermit/RCS/ckmco2.c,v $
  3.  *------------------------------------------------------------------
  4.  * $Log:    ckmco2.c,v $
  5.  * Revision 1.9  91/12/27  21:28:52  fdc
  6.  * Change fatal to macfatal, make sure all lines width 80 or less.
  7.  * 
  8.  * Revision 1.8  91/12/15  23:16:45  rick
  9.  * ut9
  10.  * 
  11.  * Revision 1.7  91/10/13  13:43:05  rick
  12.  * UT(7)
  13.  * 
  14.  * Revision 1.6  91/10/01  12:16:12  rick
  15.  * UT(5)
  16.  * 
  17.  * Revision 1.5  91/09/25  12:16:26  rick
  18.  * Command window in TE. Multiple vt100 windows for command window.
  19.  * 
  20.  * Revision 1.4  91/09/12  21:50:31  rick
  21.  * UT(3). Install on watsun
  22.  * 
  23.  * Revision 1.3  1991/09/12  16:42:51  rick
  24.  * Cleanups.
  25.  *
  26.  * Revision 1.2  1991/09/10  22:21:37  rick
  27.  * Update to UTexas(2)
  28.  *
  29.  * Revision 1.1  1991/09/10  19:17:45  rick
  30.  * Initial revision
  31.  *
  32.  *------------------------------------------------------------------
  33.  * $Endlog$
  34.  */
  35.  
  36. /*
  37.  * FILE ckmco2.c
  38.  *
  39.  * Module of mackermit: contains code for dealing with the Mac side
  40.  * of terminal emulation.
  41.  */
  42.  
  43. /*
  44.   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  45.   York.  Permission is granted to any individual or institution to use this
  46.   software as long as it is not sold for profit.  This copyright notice must be
  47.   retained.  This software may not be included in commercial products without
  48.   written permission of Columbia University.
  49. */
  50. #include "ckcdeb.h"
  51. #include "ckcasc.h"
  52. #include "ckmdef.h"
  53. #include "ckmasm.h"        /* Assembler code */
  54. #include "ckmres.h"        /* kermit resources */
  55. #include "ckmcon.h"        /* defines, etc. for terminal emulator */
  56. #include "ckmptp.h"        /* ckm* Prototypes */
  57.  
  58. extern int escape;
  59.  
  60. #define ABS(a)    ((a) < 0 ? -(a) : (a))
  61.  
  62. char **myclip_h;        /* internal clipboard */
  63. int myclip_size;        /* size of above */
  64. int my_scrapcount;        /* the value of PScrapStuff->scrapCount when we cut */
  65.  
  66. extern Boolean usingRAMdriver,
  67.            have_128roms;    /* true if we are a Plus or better */
  68.  
  69. RgnHandle dummyRgn;        /* dummy region for ScrollRect */
  70.                 /* Initialized in mac_init */
  71.  
  72. long MyCaretTime;        /* (UoR) ticks between flashes */
  73.  
  74. extern Cursor *textcurs, *normcurs, *watchcurs;    /* mouse cursor shapes */
  75.  
  76. extern    int        to_printer;        /*JAO*/
  77. extern    int        to_screen;        /*JAO*/
  78. extern    int        printer_is_on_line_num;    /*JAO*/
  79. extern    Handle    hPrintBuffer;            /*JAO*/
  80. extern    long    lPrintBufferSize;        /*JAO*/
  81. extern    long    lPrintBufferChars;        /*JAO*/
  82. extern    long    lPrintBufferAt;            /*JAO*/
  83.  
  84. extern    DialogPtr    bufferingDialog;    /*JAO*/
  85. extern    DialogPtr    overflowingDialog;    /*JAO*/
  86.  
  87. extern    MenuHandle menus[];    /* handle on our menus */  /*JAO*/
  88.  
  89. /* keyboard handling stuff */
  90.  
  91. extern char keytable[512];    /* the key redefintion flag table */
  92. extern modrec modtable[NUMOFMODS];    /* modifier records */
  93.  
  94. #define myKeyCodeMask    0x7F00
  95. #define keyModifierMask    0x1F00
  96. #define ctrlCodeMask    0x1F
  97. #define metaOrBits    0x80
  98.  
  99. #define UnmodMask    0x80        /* action bits */
  100. #define CapsMask    0x40
  101. #define CtrlMask    0x20
  102. #define MetaMask    0x10
  103.  
  104.  
  105. Boolean have_scriptmgr = FALSE;
  106.  
  107. long old_KCHR, old_SICN;    /* pointers to current system key script, icon */
  108. long cur_KCHR;
  109. Cursor *lastCursor=0L;            /* what we set the cursor to last */
  110.  
  111.  
  112. /****************************************************************************/
  113. /****************************************************************************/
  114. /****************************************************************************/
  115. /* keyboard event handling routines                                         */
  116. /****************************************************************************/
  117.  
  118.  
  119. InitKeyStuff()
  120. {
  121.     have_scriptmgr = NGetTrapAddress(num_UnknownTrap, 1) !=
  122.              NGetTrapAddress(num_ScriptTrap, 1);
  123.              
  124.     if (have_scriptmgr) {
  125.     old_KCHR = GetScript( smRoman, smScriptKeys);
  126.     old_SICN = GetScript( smRoman, smScriptIcon);
  127.     }
  128.     cur_KCHR = old_KCHR;
  129.  
  130.     UpdateOptKey(1);    /* get things set right initially */
  131. }
  132.  
  133. UpdateOptKey(int enable)
  134. {
  135.     int i;
  136.     int futzit = 0;
  137.     
  138.     if (enable) {
  139.     for (i = 0; i < NUMOFMODS; i++) {
  140.     /* shift what to look for into high byte */
  141.         if ((modtable[i].modbits) & (optionKey >> 4))
  142.                 /* if Option is selected */
  143.             futzit = 1;
  144.     }
  145.     } else {    /* allways turn off when disabling window */
  146.         futzit = 0;
  147.     }
  148.     
  149.     (void) FutzOptKey(futzit);
  150. }
  151.  
  152. FutzOptKey(int enable)
  153. {
  154.     int err;
  155.     
  156.     if (have_scriptmgr) {        /* if we are system 4.1 or later... */
  157.     if (enable) {    /* no deadkeys */
  158.         if (cur_KCHR != old_KCHR)
  159.         return (1);    /* we are allready fine */
  160.         if (GetEnvirons(smKeyScript) == smRoman) {
  161.         /* set the key map only if in roman script */
  162.         err = SetScript (smRoman, smScriptKeys, NODEAD_KCHR);
  163.         if (err != noErr) {
  164.             printerr ("Trouble setting custom keymap (KCHR):", err);
  165.             return (0);
  166.         }
  167.         /* set the icon */
  168.         err = SetScript (smRoman, smScriptIcon, NODEAD_SICN);
  169.         if (err != noErr) {
  170.             printerr ("Trouble setting custom keymap icon (SICN):",
  171.                   err);
  172.             return (0);
  173.         }
  174.         KeyScript (smRoman);
  175.         cur_KCHR = NODEAD_KCHR;
  176.         return (1);    /* success! */
  177.         } else {
  178.       printerr("Can't disable Option key -- you have a non-US keyboard",0);
  179.             return (0);
  180.         }
  181.     } else {    /* back to normal */
  182.         if (cur_KCHR == old_KCHR)
  183.         return (1);    /* we are allready fine */
  184.         /* set the key map */
  185.         err = SetScript (smRoman, smScriptKeys, old_KCHR);
  186.         if (err != noErr) {
  187.         printerr ("Trouble resetting default keymap (KCHR):", err);
  188.         return (0);
  189.         }
  190.         /* set the icon */
  191.         err = SetScript (smRoman, smScriptIcon, old_SICN);
  192.         if (err != noErr) {
  193.         printerr ("Trouble resetting default keymap icon (SICN):",
  194.               err);
  195.         return (0);
  196.         }
  197.         KeyScript (smRoman);
  198.         cur_KCHR = old_KCHR;
  199.         return (1);        /* success! */
  200.     }
  201.     } else {
  202.     /* do something or other to do the old way */
  203.     /* printerr("Kermit can't disable Option on old systems",0); */
  204.     }
  205.     return (0);
  206. }
  207.  
  208.  
  209. /****************************************************************************/
  210. /* return the ASCII character which is generated by the keyCode specified */
  211. /* with no modifiers pressed */
  212. /****************************************************************************/
  213. unsigned char DeModifyChar (long keyCode, long modifiers)
  214. {
  215.     long c;
  216.     long mystate;
  217.     short s_keycode;
  218.     Handle kchr_h;
  219.     THz curZone;
  220.  
  221. #ifdef COMMENT
  222.     ProcHandle KeyTrans;
  223.  
  224.     if (keyCode > 64)
  225.     KeyTrans = (ProcHandle) 0x2A2;    /* keypad decode */
  226.     else
  227.     KeyTrans = (ProcHandle) 0x29E;    /* keyboard decode */
  228.  
  229.     SaveRegs ();        /* save all registers */
  230.     AllRegs ();
  231.  
  232.     /* setup regs for procedure call */
  233.     /* loadD1 ((long) modifiers); */        /* no modifiers */
  234.     loadD1 ((long) 0);        /* no modifiers */
  235.     loadD2 ((long) keyCode);    /* set the keycode */
  236.     loadA0 (*KeyTrans);        /* load the content of Key1Trans to A0 */
  237.  
  238.     /* run the translation routine */
  239.     execute ();            /* call the Key1Trans procedure */
  240.  
  241.     /* move the result from reg D0 to c */
  242.     loadA0 (&c);        /* set destination address */
  243.     pushD0 ();            /* move register D0 to stack */
  244.     poptoA0 ();            /* load the stacktop to (A0) */
  245.  
  246.     RestoreRegs ();        /* restore all registers */
  247.     AllRegs ();
  248.  
  249. #endif /* COMMENT */
  250.  
  251.     if (have_scriptmgr) {        /* if we are system 4.1 or later... */
  252.         mystate = 0;
  253.     
  254.     kchr_h = GetResource('KCHR', cur_KCHR);
  255.     if (kchr_h == NIL) {
  256.         printerr("DeModifyChar: couldn't get KCHR address",0);
  257.         return(0);
  258.     }
  259.     LoadResource(kchr_h);
  260.     HLock(kchr_h);
  261.     
  262.     s_keycode = (modifiers & 0xff00) | (keyCode & 0xff);
  263.  
  264.     c = KeyTrans(*kchr_h, s_keycode, &mystate);
  265.     HUnlock(kchr_h);
  266.     curZone = GetZone();        /* as per John Norstad's (Disinfectant) */
  267.     SetZone(HandleZone(kchr_h));    /* "Toolbox Gotchas" */
  268.     ReleaseResource(kchr_h);
  269.     SetZone(curZone);
  270.     }    
  271.     return (c);
  272. }                /* DeModifyChar */
  273.  
  274.  
  275.  
  276. unsigned char obuf[2] = {1, 0};    /* single char output buffer */
  277.  
  278. /****************************************************************************/
  279. /* send a character to the line if it is in ASCII range. Do local echo if */
  280. /* necessary */
  281. /****************************************************************************/
  282. OutputChar (struct termw *termw, unsigned char c)
  283. {
  284.  
  285.     /*
  286.      * PWP: NO 7 bit masking!!!  If we do this, then I can't use Emacs, and
  287.      * the European users will be VERY unhappy, 'cause they won't be able to
  288.      * send all of their characters.
  289.      */
  290.  
  291.     obuf[1] = c;        /* store character */
  292.     writeps (obuf);        /* and write it out */
  293.  
  294.     if (duplex != 0) {
  295.     cursor_erase (termw);    /* remove from screen */
  296.     printem (termw, &obuf[1], 1);    /* Echo the char to the screen */
  297.     flushbuf(termw);        /* flush the character */
  298.     cursor_draw(termw);        /* put it back */
  299.     }
  300. }                /* OutputChar */
  301.  
  302. #ifdef COMMENT
  303. /****************************************************************************/
  304. /* Bittest returns the setting of an element in a Pascal PACKED ARRAY [0..n]
  305.    OF Boolean such as the KeyMap argument returned by GetKey
  306. /****************************************************************************/
  307. Boolean
  308. bittest (bitmap, bitnum)
  309. char bitmap[];
  310. int bitnum;
  311. {
  312.     return (0x01 & (bitmap[bitnum / 8] >> (bitnum % 8)));
  313. }                /* bittest */
  314.  
  315. /* PWP: or, as a macro, */
  316. #define bittest(bitmap,bitnum)    (0x01 & (bitmap[bitnum / 8] >> (bitnum % 8)))
  317.  
  318. #endif /* COMMENT */
  319.  
  320.  
  321. /****************************************************************************/
  322. /* Process a character received from the keyboard */
  323. /****************************************************************************/
  324. handle_char (struct termw *termw, EventRecord *evt)
  325. {
  326.     short i;
  327.     short len;
  328.     short theCode;
  329.     short modCode;
  330.     short theModBits;
  331.     char flags;
  332.     char tmpstr[256];
  333.     unsigned char c;
  334.  
  335.     /* (UoR) check for auto repeated keys */
  336.     if ((termw->autorepeat == FALSE) && (evt->what == autoKey))
  337.     return;
  338.  
  339.     ObscureCursor ();        /* PWP: hide the cursor until next move */
  340.  
  341.     modCode = evt->modifiers & keyModifierMask;
  342.     theCode = ((evt->message & myKeyCodeMask) >> 8) + (modCode >> 1);
  343.     
  344.     /* check for a special code for this key */
  345.     if (BitTst (keytable, theCode)) {
  346.     GetMacro (theCode, &flags, tmpstr);    /* get the macrostring */
  347.  
  348.     if (flags) {        /* check special flags */
  349.         switch (flags) {
  350.           case shortBreak:
  351.         sendbreak (5);
  352.         return;
  353.  
  354.           case longBreak:
  355.         sendbreak (70);
  356.         return;
  357.  
  358.           case leftArrowKey:
  359.         do_arrow (termw, leftARROW);
  360.         return;
  361.  
  362.           case rightArrowKey:
  363.         do_arrow (termw, rightARROW);
  364.         return;
  365.  
  366.           case upArrowKey:
  367.         do_arrow (termw, UPARROW);
  368.         return;
  369.  
  370.           case downArrowKey:
  371.         do_arrow (termw, DOWNARROW);
  372.         return;
  373.         
  374.           case keycomma:
  375.           case keyminus:
  376.           case keyperiod:
  377.           /* there is no keyslash */
  378.           case key0:
  379.           case key1:
  380.           case key2:
  381.           case key3:
  382.           case key4:
  383.           case key5:
  384.           case key6:
  385.           case key7:
  386.           case key8:
  387.           case key9:
  388.         do_keypad(termw, flags - keycomma);
  389.         return;
  390.         
  391.           case keypf1:
  392.           case keypf2:
  393.           case keypf3:
  394.           case keypf4:
  395.         do_pfkey(termw, flags - keypf1);
  396.         return;
  397.         
  398.           case keyenter:
  399.         do_keyenter(termw);
  400.         return;        
  401.         }
  402.     }
  403.     /* send key macro string */
  404.  
  405.     /*
  406.      * PWP: note, we DON'T have to convert it to a Pascal string, 'cause
  407.      * the macros are now stored as Pascal strings
  408.      */
  409.     writeps (tmpstr);    /* send it to the line */
  410.     if (duplex != 0)
  411.         printps(termw,tmpstr);    /* echo it locally */
  412.     return;
  413.     }
  414.     for (i = 0; i < NUMOFMODS; i++) {
  415.     /* shift what to look for into high byte */
  416.     theModBits = modtable[i].modbits << 4;
  417.     len = strlen (modtable[i].prefix);
  418.  
  419.     if ((theModBits || len) &&
  420.         ((theModBits & modCode) == (theModBits & keyModifierMask))) {
  421.         /* send prefix if there is one */
  422.         if (len) {
  423.         /* PWP: these are saved as Pascal strings now */
  424.         BlockMove (modtable[i].prefix, tmpstr,
  425.                (modtable[i].prefix[0] + 1));
  426.         writeps (tmpstr);    /* send it to the line */
  427.         if (duplex != 0)
  428.             printps(termw,tmpstr);    /* echo it locally */
  429.         }
  430.  
  431.         /*
  432.          * get the unmodified ASCII code if the unmodify action bit is
  433.          * active
  434.          */
  435.         if (theModBits & UnmodMask)
  436.         c = DeModifyChar ((long) ((evt->message & myKeyCodeMask) >> 8),
  437.                   (long) (modCode & shiftKey));
  438.              /* PWP: we pass through the shiftedness of this key */
  439.         else
  440.         c = evt->message & charCodeMask;    /* otherwise get the
  441.                              * standard char */
  442.  
  443.         /* make an uppercase character if the caps action bit is active */
  444.         if ((theModBits & CapsMask) && islower (c))
  445.         c = toupper (c);
  446.  
  447.         /* make a control character if the control action bit is active */
  448.         if (theModBits & CtrlMask)
  449.         c &= ctrlCodeMask;
  450.  
  451.         /* PWP: for Meta characters (yes, I use Emacs) */
  452.         if (theModBits & MetaMask)
  453.         c |= metaOrBits;
  454.  
  455.         if (!checkescape(c))
  456.         OutputChar (termw, c);
  457.         return;
  458.     }            /* if */
  459.     }                /* for */
  460.  
  461.     /* get the ASCII code and send it */
  462.     c = evt->message & charCodeMask;
  463.     if (!checkescape(c))
  464.     OutputChar(termw, c);
  465. }                /* handle_char */
  466.  
  467.  
  468. /*
  469.  * checkescape
  470.  * Handle escape sequences in connected mode
  471.  * Return TRUE if character used.
  472.  */
  473. #define NKBUF 10
  474. checkescape (char c)
  475. {
  476.     int x;
  477.     static int esclevel = 0;
  478.     static char *kbp, kbuf[NKBUF];
  479.     extern int cmdmsk;
  480.  
  481.     switch (esclevel) {
  482.     case 0:                /* no escapes pending */
  483.     if ((c & 0x7f) == escape) {
  484.         esclevel++;
  485.         return TRUE;        /* we ate the char */
  486.     }
  487.     return FALSE;            /* we did not process char */
  488.  
  489.     case 1:                /* process escape command */
  490.     if (doesc(c)) {            /* if CMDQ */
  491.         esclevel++;
  492.         kbp = kbuf;            /* preset buffer */
  493.         *kbp++ = CMDQ;
  494.     }
  495.     else
  496.         esclevel = 0;
  497.     return TRUE;            /* we ate the char */
  498.  
  499.     case 2:                /* quoted backslash sequence */
  500.     c &= cmdmsk;
  501.     *kbp = c;
  502.     if ((c != '\r') && (c != '\n')) {
  503.         if (&kbuf[NKBUF-1] != kbp)    /* if buffer not full */
  504.         kbp++;
  505.         return TRUE;
  506.     }
  507.     *kbp = 0;
  508.     esclevel = 0;
  509.  
  510.     kbp = kbuf;
  511.     x = xxesc(&kbp);
  512.     if (x >= 0) {
  513.         c = dopar(x);
  514.         ttoc(c);
  515.     } else {        /* Invalid backslash code. */
  516.         putchar(BEL);
  517.     }
  518.     return TRUE;
  519.     }
  520. }
  521.  
  522.  
  523. /*
  524.  * console_char
  525.  * Handle keyboard events while not connected
  526.  * Return TRUE if we inserted a character into the console buffer.
  527.  *
  528.  * THIS ROUTINE LIKELY NEEDS MORE WORK HANDLING SPECIAL CHARACTERS.
  529.  * 
  530.  */
  531. console_char (struct termw *termw, EventRecord *evt)
  532. {
  533.     short i;
  534.     short len;
  535.     short theCode;
  536.     short modCode;
  537.     short theModBits;
  538.     char flags;
  539.     char tmpstr[256];
  540.     unsigned char c;
  541.  
  542.     /* (UoR) check for auto repeated keys */
  543.     if ((termw->autorepeat == FALSE) && (evt->what == autoKey))
  544.     return;
  545.  
  546.     ObscureCursor ();        /* PWP: hide the cursor until next move */
  547.  
  548.     modCode = evt->modifiers & keyModifierMask;
  549.     theCode = ((evt->message & myKeyCodeMask) >> 8) + (modCode >> 1);
  550.     
  551.     /* check for a special code for this key */
  552.     if (BitTst (keytable, theCode)) {
  553.     GetMacro (theCode, &flags, tmpstr); /* get the macrostring */
  554.  
  555.     if (flags) {            /* check special flags */
  556.         switch (flags) {
  557.         case shortBreak:
  558. /*        sendbreak (5); */
  559.         return FALSE;
  560.  
  561.         case longBreak:
  562. /*        sendbreak (70); */
  563.         return FALSE;
  564.  
  565.         case leftArrowKey:
  566. /*         do_arrow (leftARROW); */
  567.         return FALSE;
  568.  
  569.         case rightArrowKey:
  570. /*         do_arrow (rightARROW); */
  571.         return FALSE;
  572.  
  573.         case upArrowKey:
  574. /*         do_arrow (UPARROW); */
  575.         return FALSE;
  576.  
  577.         case downArrowKey:
  578. /*         do_arrow (DOWNARROW); */
  579.         return FALSE;
  580.         
  581.         case keycomma:
  582.         case keyminus:
  583.         case keyperiod:
  584.         /* there is no keyslash */
  585.         case key0:
  586.         case key1:
  587.         case key2:
  588.         case key3:
  589.         case key4:
  590.         case key5:
  591.         case key6:
  592.         case key7:
  593.         case key8:
  594.         case key9:
  595. /*        do_keypad(flags - keycomma); */
  596.         return FALSE;
  597.         
  598.         case keypf1:
  599.         case keypf2:
  600.         case keypf3:
  601.         case keypf4:
  602. /*        do_pfkey(flags - keypf1); */
  603.         return FALSE;
  604.         
  605.         case keyenter:
  606. /*        do_keyenter(); */
  607.         return FALSE;        
  608.         }
  609.     }
  610.     /* send key macro string */
  611.     writecb(tmpstr);
  612.     return TRUE;
  613.     }
  614.  
  615.     for (i = 0; i < NUMOFMODS; i++) {
  616.     /* shift what to look for into high byte */
  617.     theModBits = modtable[i].modbits << 4;
  618.     len = strlen (modtable[i].prefix);
  619.  
  620.     if ((theModBits || len) &&
  621.         ((theModBits & modCode) == (theModBits & keyModifierMask))) {
  622.         /* send prefix if there is one */
  623.         if (len) {
  624.         /* PWP: these are saved as Pascal strings now */
  625.         BlockMove (modtable[i].prefix, tmpstr, 
  626.                (modtable[i].prefix[0] + 1));
  627.         writecb(tmpstr);    /* put in console buffer */
  628.         if (duplex != 0)
  629.             printps(termw,tmpstr);    /* echo it locally */
  630.         }
  631.  
  632.         /*
  633.          * get the unmodified ASCII code if the unmodify action bit is
  634.          * active
  635.          */
  636.         if (theModBits & UnmodMask)
  637.         c = DeModifyChar ((long) ((evt->message & myKeyCodeMask) >> 8),
  638.                   (long) (modCode & shiftKey));
  639.         /* PWP: we pass through the shiftedness of this key */
  640.         else
  641.         c = evt->message & charCodeMask; /* otherwise get the
  642.                           * standard char */
  643.  
  644.         /* make an uppercase character if the caps action bit is active */
  645.         if ((theModBits & CapsMask) && islower (c))
  646.         c = toupper (c);
  647.  
  648.         /* make a control character if the control action bit is active */
  649.         if (theModBits & CtrlMask)
  650.         c &= ctrlCodeMask;
  651.  
  652.         /* PWP: for Meta characters (yes, I use Emacs) */
  653.         if (theModBits & MetaMask)
  654.         c |= metaOrBits;
  655.  
  656.         writecbc(c);
  657.         return TRUE;
  658.     }                /* if */
  659.     }                    /* for */
  660.  
  661.     /* get the ASCII code and send it */
  662.     writecbc(evt->message & charCodeMask);
  663.     return TRUE;
  664. }
  665.  
  666.  
  667. /****************************************************************************/
  668. /****************************************************************************/
  669. /****************************************************************************/
  670. /* general rectangle routines                                               */
  671. /****************************************************************************/
  672.  
  673.  
  674.  
  675. /****************************************************************************/
  676. /*
  677.  * Routine makerect
  678.  *
  679.  * Make a rectangle in r starting on line lin and column col extending
  680.  * numlin lines and numcol characters.
  681.  *
  682.  */
  683. /****************************************************************************/
  684. void
  685. makerect(struct termw *termw, Rect *r,int lin, int col, int numlin,
  686.      int numcol)
  687. {
  688.     r->top = lin * termw->lineheight + TOPMARGIN;
  689.     r->left = col * termw->charwidth + LEFTMARGIN;
  690.     r->bottom = r->top + numlin * termw->lineheight;
  691.     r->right = r->left + numcol * termw->charwidth;
  692. }                /* makerect */
  693.  
  694. /* the (almost) inverse of makerect() */
  695. void
  696. recttocharpos(struct termw *termw, Rect *r, int *toplin_p, int *leftcol_p,
  697.           int *botlin_p, int *rightcol_p)
  698. {
  699.     /* Inverse of makerect(): find the bounding chars (rounding outward) */
  700.     *toplin_p = (r->top - TOPMARGIN) / termw->lineheight;
  701.     *botlin_p = (r->bottom - TOPMARGIN + termw->lineheight - 1)
  702.     / termw->lineheight;
  703.     *leftcol_p = (r->left - LEFTMARGIN) / termw->charwidth;
  704.     *rightcol_p = (r->right - LEFTMARGIN + termw->charwidth - 1)
  705.     / termw->charwidth;
  706.  
  707.     /* bounds limit it to the actual screen area */
  708.     if (*toplin_p < 0) *toplin_p = 0;
  709.     if (*botlin_p > termw->screensize) *botlin_p = termw->screensize;
  710.     if (*leftcol_p < 0) *leftcol_p = 0;
  711.     if (*rightcol_p > MAXCOL) *rightcol_p = MAXCOL;
  712. }
  713.  
  714. /* (PWP) do what makerect does, then invert the rect */
  715. void
  716. invertchars(struct termw *termw, int lin, int col, int numlin, int numcol)
  717. {
  718.     Rect r;
  719.     r.top = lin * termw->lineheight + TOPMARGIN;
  720.     r.left = col * termw->charwidth + LEFTMARGIN;
  721.     r.bottom = r.top + numlin * termw->lineheight;
  722.     r.right = r.left + numcol * termw->charwidth;
  723.     InvertRect (&r);
  724. }
  725.  
  726. /*
  727.  * Figure out how wide this line could be.  Not constant any more because of
  728.  * double width lines.
  729.  */
  730. int
  731. line_maxcol(struct termw *termw, int lin)
  732. {
  733.     if (termw->line_attrs[lin] != VT_SNGL)
  734.     return (MAXCOL / 2);
  735.     else
  736.     return (MAXCOL);
  737. }
  738.  
  739. /****************************************************************************/
  740. /* Connect support routines */
  741. /****************************************************************************/
  742. void term_new_font (struct termw *termw)
  743. {
  744.     FontInfo fi;
  745.     GrafPtr savePort;
  746.     
  747.     GetPort (&savePort);    /* there just has to be a better way */
  748.     SetPort (termw->window);
  749.  
  750.     SetFontLock(false);
  751.     termw->font_is_locked = false;
  752.     
  753.     TextFont(termw->current_font);    /* make sure to set this font */
  754.     TextSize(termw->current_size);
  755.     
  756.     GetFontInfo (&fi);
  757.     
  758.     termw->lineheight = fi.ascent + fi.descent + fi.leading;
  759.     termw->chardescent = fi.descent;
  760.     /* termw->charwidth = fi.widMax; */
  761.     termw->charwidth = CharWidth('W');        /* idea from NCSA telnet 2.3 */
  762.  
  763.     SetPort (savePort);        /* there just has to be a better way */
  764. }
  765.     
  766. /* consetup is called once at startup */
  767. struct termw *consetup (int boxid)
  768. {
  769.     struct termw *termw;
  770.     GrafPtr savePort;
  771.     extern struct termw *termwl;
  772.     
  773.     termw = (struct termw *)malloc(sizeof(struct termw));
  774.     if (!termw)
  775.     macfatal("consetup: no memory for terminal window", 0);
  776.     bzero((char *)termw, sizeof(struct termw));
  777.     termw->next = termwl;        /* add to list */
  778.     termwl = termw;
  779.     termw->current_font = VT100FONT;
  780.     termw->current_size = 9;
  781.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  782.     termw->oldlin = -1;
  783.     termw->from_lin = -1;
  784.     termw->screensize = INIT_SCREENSIZE; /* number of lines on screen */
  785.     termw->graphicsinset[0] = ASCII_SET;
  786.     termw->graphicsinset[1] = ASCII_SET;
  787.     termw->graphicsinset[2] = LAT1_SET;
  788.     termw->graphicsinset[3] = LAT1_SET;
  789.     termw->Gr_set = 1;            /* (PWP) current chosen RH set */
  790.     termw->old_Gl_set = -1;        /* set to come back to after */
  791.                     /* single shift GL */
  792.     termw->autowrap = TRUE;        /* Autowrap on by default */
  793.     termw->autorepeat = TRUE;        /* (UoR) auto repeat flag */
  794.     termw->dispcontchar = TRUE;        /* do not show control characters */
  795.     termw->blockcursor = TRUE;        /* show block or underline cursor */
  796.     termw->cursor_shown = TRUE;        /* (PWP) show the cursor */
  797.     termw->blinkcursor = TRUE;        /* true if we make the cursor blink */
  798.     termw->charflg = CF_OUTC;        /* state variable */
  799.  
  800.     setWindowLoc(boxid);
  801. #ifdef notdef
  802.     termw->window = GetNewWindow (boxid, (Ptr) &termw->terminalWRec, 
  803.                  (WindowPtr) -1L);
  804. #else
  805.     termw->window = GetNewWindow (boxid, (Ptr) 0L, (WindowPtr) -1L);
  806. #endif
  807.  
  808.     GetPort (&savePort);    /* there just has to be a better way */
  809.     SetPort (termw->window);
  810.  
  811.     PenMode (srcCopy);        /* (PWP) was patXor */
  812.     flushio ();            /* Get rid of pending characters */
  813.  
  814.     termw->current_font = VT100FONT;    /* (UoR) Set initial font to VT100 */
  815.     termw->current_size = 9;
  816.     
  817.     if (termw->screeninvert)
  818.     TextMode (srcBic);
  819.     else
  820.     TextMode (srcOr);
  821.     TextFace (0);        /* PWP: be safe.  We allways stay like this */
  822.  
  823.     init_term(termw);        /* Set up some terminal variables */
  824.  
  825.     /* reset the font (chosen above) */
  826.     term_new_font(termw);
  827.     /* doesn't change #lines, but size of a line has changed */
  828.     grow_term_to(termw,termw->screensize);
  829.  
  830.     /* normal char mode, home cursor, clear screen, and save position */
  831.     norm_home_clear_save(termw);
  832.  
  833.     cursor_draw(termw);        /* (UoR) be sure to draw it */
  834.  
  835.     SetPort (savePort);        /* there just has to be a better way */
  836.     
  837.     return termw;
  838. }                /* consetup */
  839.  
  840. void term_reset (struct termw *termw)
  841. {
  842.     GrafPtr savePort;
  843.     
  844.     GetPort (&savePort);    /* there just has to be a better way */
  845.     SetPort (termw->window);
  846.  
  847.     PenMode (srcCopy);        /* (PWP) was patXor */
  848.     flushio ();            /* Get rid of pending characters */
  849.     screen_to_bottom(termw);    /* slide the visible region to active area */
  850.  
  851.     termw->graphicsinset[0] = ASCII_SET;
  852.     termw->graphicsinset[1] = GRAF_SET;
  853.     termw->Gl_set = 0;
  854.     termw->Gr_set = 1;
  855.     termw->textstyle = 0;
  856.     termw->current_style = 0;
  857.     termw->draw_sing_chars = 0;
  858.     termw->font_is_locked = FALSE;
  859.     termw->screeninvert = FALSE;    /* (UoR) inverted screen flag */
  860.     termw->insert = FALSE;
  861.     termw->newline = FALSE;        /* (UoR) linefeed mode by default */
  862.     termw->autowrap = TRUE;        /* Autowrap on by default */
  863.     termw->relorigin = FALSE;        /* (UoR) relative origin off */
  864.     termw->autorepeat = TRUE;        /* (UoR) auto repeat flag */
  865.     termw->appl_mode = FALSE;        /* (PWP) keypad application mode */
  866.     termw->curskey_mode = FALSE;    /* (PWP) cursor key application mode */
  867.     termw->smoothscroll = FALSE;    /* do smooth scrolling (PWP: or not) */
  868.     termw->scroll_amount = 0;        /* no pending scroll */
  869.     termw->refresh_amount = 0;        /* no pending refresh */
  870.     termw->dispcontchar = TRUE;    /* do not show control characters */
  871.     termw->blockcursor = TRUE;        /* show block or underline cursor */
  872.     termw->cursor_shown = TRUE;    /* (PWP) show the cursor */
  873.     termw->mouse_arrows = FALSE;    /* mouse down in screen does arrow keys */
  874.     termw->visible_bell = FALSE;    /* true if we do blink instead of bell */
  875.     termw->eightbit_disp = FALSE;    /* default to 7 bits */
  876.     termw->blinkcursor = TRUE;        /* true if we make the cursor blink */
  877.  
  878.  
  879.     termw->have_selection = FALSE;    /* (PWP) we have no selected text */
  880.     
  881.     termw->saved_tlin = 0;
  882.     termw->saved_blin = 0;
  883.     
  884.     termw->current_font = VT100FONT;    /* (UoR) Set initial font to VT100 */
  885.     termw->current_size = 9;
  886.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  887.  
  888.     if (termw->screeninvert)
  889.     TextMode (srcBic);
  890.     else
  891.     TextMode (srcOr);
  892.     TextFace (0);        /* PWP: be safe.  We allways stay like this */
  893.     
  894.     /* reset the font (chosen above) */
  895.     term_new_font(termw);
  896.     /* doesn't change #lines, but size of a line has changed */
  897.     grow_term_to(termw,termw->screensize);
  898.  
  899.     /* normal char mode, home cursor, clear screen, and save position */
  900.     norm_home_clear_save(termw);
  901.     
  902.     cursor_draw(termw);        /* (UoR) be sure to draw it */
  903.  
  904.     SetPort (savePort);        /* there just has to be a better way */
  905. }                /* consetup */
  906.  
  907. /****************************************************************************/
  908. /****************************************************************************/
  909.  
  910.  
  911. /*************************************************/
  912. /* cursor drawing stuff                          */
  913. /*************************************************/
  914.  
  915. Boolean cursor_rect (struct termw *termw, int line, int col, Rect *r)
  916. {
  917.     /* if cursor not on screen */
  918.     if (line - termw->display_topline >= termw->screensize)
  919.         return FALSE;
  920.     
  921.     if (col >= 80)            /* make it look like a VT100 */
  922.     col = 79;
  923.     
  924.     /* Get character rectangle */
  925.     makerect(termw,r, line - termw->display_topline, col, 1, 1);
  926.     if (!termw->blockcursor) {
  927.     r->top = r->bottom;
  928.     r->bottom = r->top + 2;
  929.     }
  930.  
  931.     return TRUE;
  932. }                    /* cursor_rect */
  933.  
  934. void cursor_draw (struct termw *termw)
  935. {
  936.     Rect r;
  937.     GrafPtr savePort;
  938.  
  939.     if (!termw->cursor_shown)         /* (PWP) not if we are hiding cursor */
  940.     return;
  941.     
  942.     GetPort (&savePort);    /* there just has to be a better way */
  943.     SetPort (termw->window);
  944.  
  945.     if (!termw->cursor_invert) {
  946.     if (cursor_rect(termw,termw->curlin, termw->curcol, &r)) {
  947.         if (termw->in_front) {
  948.         InvertRect (&r);
  949.         } else {
  950.         PenMode (patXor);
  951.         FrameRect (&r);
  952.         PenMode (patCopy);
  953.         }
  954.     }
  955.     }
  956.  
  957.     /* replace mouse cursor */
  958.     if ((termw->oldlin >= 0) && (!termw->mousecurs_drawn)) {
  959.     makerect(termw ,&r, termw->oldlin, termw->oldcol, 1, 1);
  960.     PenMode (patXor);
  961.     FrameRect (&r);
  962.     PenMode (patCopy);
  963.     termw->mousecurs_drawn = TRUE;
  964.     }
  965.     
  966.     termw->cursor_invert = TRUE;
  967.     termw->cur_drawn = TRUE;
  968.  
  969.     SetPort (savePort);        /* there just has to be a better way */
  970. }                /* cursor_draw */
  971.  
  972.  
  973. void cursor_erase (struct termw *termw)
  974. {
  975.     Rect r;
  976.     GrafPtr savePort;
  977.     
  978.     GetPort (&savePort);    /* there just has to be a better way */
  979.     SetPort (termw->window);
  980.  
  981.     if (termw->cursor_invert) {
  982.     if (cursor_rect(termw, termw->curlin, termw->curcol, &r)) {
  983.         if (termw->in_front) {
  984.         InvertRect (&r);
  985.         } else {
  986.         PenMode (patXor);
  987.         FrameRect (&r);
  988.         PenMode (patCopy);
  989.         }
  990.     }
  991.     }
  992.     /* remove mouse cursor */    
  993.     if ((termw->oldlin >= 0) && (termw->mousecurs_drawn)) {
  994.     makerect(termw ,&r, termw->oldlin, termw->oldcol, 1, 1);
  995.     PenMode (patXor);
  996.     FrameRect (&r);
  997.     PenMode (patCopy);
  998.      termw->mousecurs_drawn = FALSE;
  999.    }
  1000.  
  1001.     termw->cursor_invert = FALSE;
  1002.     termw->cur_drawn = FALSE;
  1003.  
  1004.     SetPort (savePort);        /* there just has to be a better way */
  1005. }                /* cursor_erase */
  1006.  
  1007. void flash_cursor (struct termw *termw)
  1008. {
  1009.     register long tc;
  1010.     Rect r;
  1011.     GrafPtr savePort;
  1012.     
  1013.     GetPort (&savePort);    /* there just has to be a better way */
  1014.     SetPort (termw->window);
  1015.  
  1016.     tc = TickCount ();
  1017.     if (((tc - termw->last_flash) > MyCaretTime) ||
  1018.     (tc - termw->last_flash) < 0L) {
  1019.     termw->last_flash = tc;
  1020.  
  1021.     if (termw->cur_drawn) {
  1022.         if (cursor_rect(termw,termw->curlin, termw->curcol, &r)) {
  1023.         /* PWP: only blink if asked for */
  1024.         if (termw->blinkcursor && termw->in_front) {
  1025.             InvertRect (&r);
  1026.             termw->cursor_invert = !termw->cursor_invert;
  1027.         } else if (!termw->cursor_invert) {
  1028.                 /* make sure that the cursor shows up */
  1029.             if (termw->in_front) {
  1030.             InvertRect (&r);
  1031.             } else {
  1032.             PenMode (patXor);
  1033.             FrameRect (&r);
  1034.             PenMode (patCopy);
  1035.             }
  1036.             termw->cursor_invert = TRUE;
  1037.         }
  1038.         }
  1039.     }
  1040.     }
  1041.  
  1042.     SetPort (savePort);        /* there just has to be a better way */
  1043. }                /* flash_cursor */
  1044.  
  1045.  
  1046. /****************************************************************************/
  1047. /* PWP -- like waitasec(), but don't get any characters.  Used for 
  1048.    visable bell. */
  1049. /****************************************************************************/
  1050. waitnoinput ()
  1051. {
  1052.     long ticks = 2, end_time;
  1053.  
  1054.     Delay (ticks, &end_time);    /* pause for 1/30th second */
  1055. }                /* waitnoinput */
  1056.  
  1057.  
  1058. /****************************************************************************/
  1059. /* (UoR) get any characters, and pause for a while */
  1060. /****************************************************************************/
  1061. waitasec (struct termw *termw)
  1062. {
  1063.     waitnoinput();
  1064.     inpchars(termw);
  1065. }                /* waitasec */
  1066.  
  1067.  
  1068. /****************************************************************************/
  1069. /* updateCursor -- taken from NCSA Telnet for the Macintosh, v 2.2   */
  1070. /****************************************************************************/
  1071. void updateCursor (struct termw *termw, int force, WindowPeek myfrontwindow)
  1072. {
  1073.     static Point lastPoint;
  1074.     static int optwasdown = 0;
  1075.     Cursor *thisCursor;
  1076.     int optDown;
  1077.     KeyMap allthekeys;    /* Someplace to put the keymap */
  1078.     char *cp_allthekeys = (char *) &allthekeys;    /* $$$ HACK HACK */
  1079.     int newlin, newcol;
  1080.     Point MousePt;
  1081.     Rect r;
  1082.     GrafPtr savePort;
  1083.     
  1084.     GetPort (&savePort);    /* there just has to be a better way */
  1085.     SetPort (termw->window);
  1086.  
  1087.     GetMouse(&MousePt);
  1088.  
  1089.     GetKeys(allthekeys);
  1090.     optDown = cp_allthekeys[7] & 4;    /* should be symbolic */
  1091.  
  1092.     if ( (!force) && (!in_background) && (MousePt == lastPoint) && 
  1093.     (optDown == optwasdown)) {
  1094.     SetPort (savePort);
  1095.     return;
  1096.     }
  1097.     
  1098.     if (force)
  1099.     lastCursor=0L;
  1100.     
  1101.     if (in_background) {
  1102.     lastCursor = 0L;        /* allways force if in background */
  1103.     thisCursor = normcurs;        /* default cursor shape */
  1104.     } else if (protocmd != 0) {        /* if doing a transfer */
  1105.     thisCursor = watchcurs;        /* in forground and doing a transfer */
  1106.     } else if (((myfrontwindow == termw->window) ||
  1107.         ((myfrontwindow == NIL) &&
  1108.          (FrontWindow() == termw->window))) &&
  1109.            PtInRect(MousePt, &termw->ScreenRect)) {
  1110.     if (termw->mouse_arrows || optDown) {
  1111.         newlin = (MousePt.v - TOPMARGIN) / termw->lineheight;
  1112.         newcol = (MousePt.h - LEFTMARGIN + termw->charwidth/2) / 
  1113.         termw->charwidth;
  1114.     
  1115.         if ((termw->oldlin != newlin) || (termw->oldcol != newcol)) {
  1116.         PenMode (patXor);    /* For FrameRect calls */
  1117.         if (termw->oldlin >= 0) { /* if old rectangle */
  1118.             if (termw->mousecurs_drawn) {
  1119.             makerect(termw,&r, termw->oldlin, termw->oldcol, 1, 1);
  1120.             FrameRect (&r);
  1121.             }
  1122.         } else {           /* else if drawing for the first time */
  1123.             HideCursor ();
  1124.         }
  1125.         
  1126.         makerect(termw,&r, newlin, newcol, 1, 1);
  1127.         FrameRect (&r);
  1128.         PenMode (patCopy);    /* reset to normal pen mode */
  1129.     
  1130.         termw->oldlin = newlin;
  1131.         termw->oldcol = newcol;
  1132.         termw->mousecurs_drawn = TRUE;
  1133.         }
  1134.         lastPoint=MousePt;
  1135.         optwasdown=optDown;
  1136.         SetPort (savePort);        /* there just has to be a better way */
  1137.         return;
  1138.     } else {            
  1139.         thisCursor = textcurs;
  1140.     }
  1141.     } else {
  1142.     thisCursor  = normcurs;        /* default cursor shape */
  1143.     }
  1144.     
  1145.     if  (lastCursor!= thisCursor) {
  1146.     SetCursor(thisCursor);
  1147.     lastCursor = thisCursor;
  1148.     }
  1149.  
  1150.     lastPoint=MousePt;
  1151.     optwasdown=optDown;
  1152.  
  1153.     if (termw->oldlin >= 0) {         /* if we hade drawn a movement outline */
  1154.     if (termw->mousecurs_drawn) {
  1155.         PenMode (patXor);    /* For FrameRect calls */
  1156.         makerect(termw,&r, termw->oldlin, termw->oldcol, 1, 1);
  1157.         FrameRect (&r);
  1158.     }
  1159.     
  1160.     termw->oldlin = -1;
  1161.      termw->mousecurs_drawn = FALSE;
  1162.     ShowCursor ();
  1163.     PenMode (patCopy);    /* reset to normal pen mode */
  1164.     }
  1165.  
  1166.     SetPort (savePort);        /* there just has to be a better way */
  1167. }
  1168.  
  1169.  
  1170. /****************************************************************************/
  1171. /* Put characters onto the actual screen                                    */
  1172. /****************************************************************************/
  1173.  
  1174. static int to_mac_style[] = {
  1175.     normal,    underline, italic, underline|italic,
  1176.     bold|condense, bold|condense|underline,
  1177.     bold|condense|italic, bold|condense|underline|italic
  1178. };
  1179.  
  1180. /****************************************************************************/
  1181. /* flushbuf(termw) -- draw all the buffered characters on the screen */
  1182. /****************************************************************************/
  1183. void flushbuf (struct termw *termw)
  1184. {
  1185.     register int i, scrl_amt;
  1186.  
  1187.     if (termw->out_maxcol == 0)
  1188.     return;            /* Nothing to flush */
  1189.  
  1190.     if (to_printer) {                    /*JAO*/
  1191.     for (i = termw->out_mincol; i < termw->out_maxcol; i++) {
  1192.         (*hPrintBuffer)[lPrintBufferAt++] = 
  1193.         termw->scr[termw->curlin+termw->display_topline][i];
  1194.         if (lPrintBufferAt == lPrintBufferSize)
  1195.         lPrintBufferAt = 0L;
  1196.         lPrintBufferChars++;
  1197.         if (lPrintBufferChars == 1L)
  1198.         updatepstat();
  1199.         if (lPrintBufferChars == lPrintBufferSize) {
  1200.         overflowingDialog = GetNewDialog(OVERFLOWINGBOXID, NILPTR, 
  1201.                          (WindowPtr) - 1);
  1202.         DrawDialog(overflowingDialog);
  1203.         break;                    /* PWP */
  1204.         }
  1205.     }
  1206.     }
  1207.  
  1208.     if (!to_screen) {
  1209.     termw->out_maxcol = 0;        /* Say no more chars to output */
  1210.     return;                /*JAO*/
  1211.     }
  1212.     
  1213.     /* save because flushscroll() resets scroll_amount */
  1214.     scrl_amt = termw->scroll_amount;
  1215. #ifdef COMMENT
  1216.     if (scrl_amt) {
  1217.     /*
  1218.      * If we have pending scrolling, and we are about to draw outside 
  1219.      * of the region that will be refreshed when the scrolling happens, 
  1220.      * do the scrolling now.
  1221.      */
  1222.         if ((termw->refresh_amount < 0) && 
  1223.         ((termw->curlin < termw->saved_blin + termw->refresh_amount)
  1224.          || (termw->curlin > termw->saved_blin)))
  1225.     {
  1226.         flushscroll(termw);
  1227.     }
  1228.     else if ((termw->refresh_amount > 0) && 
  1229.          ((termw->curlin < termw->saved_tlin)
  1230.           || (termw->curlin
  1231.               > termw->saved_tlin + termw->refresh_amount)))
  1232.     {
  1233.         flushscroll(termw);
  1234.     }
  1235.     else
  1236.     {
  1237.         termw->out_maxcol = 0;    /* Say no more chars to output */
  1238.         return;
  1239.     }
  1240.     }
  1241. #endif /* COMMENT */
  1242.  
  1243.     if (scrl_amt)
  1244.     flushscroll(termw);
  1245.  
  1246.     if (termw->have_selection)
  1247.     maybe_nuke_selection (termw, termw->curlin, termw->curlin);
  1248.  
  1249.     if (!termw->out_maxcol)    /* if already drawn this line, return */
  1250.     return;
  1251.  
  1252.     /*
  1253.      * PWP: Why have two routines to do the same thing?  I centralized
  1254.      * all the font crap into draw_line_w_attrs so I didn't need
  1255.      * to keep track of code here too.  Side benifit -- we can nuke
  1256.      * the outbuf array.
  1257.      *
  1258.      * Note that in draw_line_w_attrs(), the left and right columns are
  1259.      * SCREEN columns, not virtual buffer columns.  Theses are usually
  1260.      * the same, unless we happen to be drawing onto a double-width line.
  1261.      */
  1262.     if (termw->line_attrs[termw->curlin] == VT_SNGL) {
  1263.     /* single-width (normal) line */
  1264.     draw_line_w_attrs(termw, termw->curlin + termw->display_topline, 
  1265.               termw->curlin, termw->out_mincol, termw->out_maxcol, 
  1266.               (scrl_amt == 0));
  1267.     } else {
  1268.     /* line with double width characters */
  1269.     draw_line_w_attrs(termw, termw->curlin + termw->display_topline, 
  1270.               termw->curlin, 2 * termw->out_mincol,
  1271.               2 * termw->out_maxcol, (scrl_amt == 0));
  1272.     }
  1273.     termw->out_maxcol = 0;        /* Say no more chars to output */
  1274. }                /* flushbuf */
  1275.  
  1276. /****************************************************************************/
  1277. /* set_style(termw, style)
  1278.  - set the correct stuff for displaying chars in style   */
  1279. /****************************************************************************/
  1280. void set_style (struct termw *termw, int style)
  1281. {
  1282.     int m_sty, m_font;
  1283.     static int o_sty = 0, o_font = 0;
  1284.     
  1285.     if (style == termw->current_style) 
  1286.     return;
  1287.     termw->current_style = style;
  1288.     
  1289.     m_sty = to_mac_style[style & STY_MSTY];
  1290.     m_font = ((style & STY_FONT) >> 3) + termw->current_font;
  1291.     termw->draw_sing_chars = ((style & VT_BLINK)
  1292.                   || (CharWidth('W')!=CharWidth('i'))
  1293.                   || (!RealFont(termw->current_font,
  1294.                         termw->current_size)));
  1295.     /* printerr("draw_sing_chars == ", draw_sing_chars); */
  1296.  
  1297.     if (!have_128roms && (m_sty & bold)) {   /* if on an old mac and bolding */
  1298.     if (m_font == VT100FONT) {
  1299.         m_font = VT100BOLD;
  1300.         m_sty &= ~(bold|condense);
  1301.     } else {
  1302.         termw->draw_sing_chars = 1;
  1303.     }
  1304.     }
  1305.  
  1306.     if (m_font != o_font) {
  1307.     TextFont (m_font);        /* new font */
  1308.     o_font = m_font;
  1309.     }
  1310.     if (m_sty != o_sty) {
  1311.     TextFace (m_sty);        /* new text face */
  1312.     o_sty = m_sty;
  1313.     }
  1314. }
  1315.  
  1316. /****************************************************************************
  1317.  * draw_line_w_attrs() -- draw the line including all character attributes
  1318.  * that is in the terminal buffer at line "lin" onto the screen at vertical
  1319.  * character offset "v", in as little time as possible.
  1320.  *
  1321.  * It seems to speed things up just a tad to skip leading and trailing
  1322.  * whitespace on the line, so we can draw only the characters in the middle.
  1323.  * On the other hand, it doesn't save any time to find the individual words
  1324.  * and draw just those.  Likewise, if we have to draw the line one character
  1325.  * at a time it is really slow. 
  1326.  *
  1327.  * Perhaps a later version of Kermit could take the current fonts and build 
  1328.  * custom set of fixed width fonts (a'la BitFont), and then use that to draw
  1329.  * characters onto the screen.
  1330.  *
  1331.  * Another later addition could be correct handling of double width and double
  1332.  * height characters, by drawing the characters into an off-screen bitmap,
  1333.  * and then using CopyBits to stretch the characters to fit.
  1334.  */
  1335.  
  1336. void draw_line_w_attrs (struct termw *termw, register int lin, register int v,
  1337.           register int l_col, register int r_col,
  1338.           int must_drawblanks)
  1339. {
  1340.     register int o, i, j, sty;
  1341.     register char *cp, *ap, *line_ch, *line_at;
  1342.     register int min, max;
  1343.     register int lines_attrs;
  1344.     int orig_l_col;
  1345.     Rect r;
  1346.     
  1347.     if (!termw)
  1348.     DebugStr("\ptermw == NULL");
  1349.  
  1350.     /* this routine CAN be called with scrolling_region non-zero */
  1351.     
  1352.     /* bounds limit the min and max columns */
  1353.     if (l_col < 0) l_col = 0;
  1354.     if (l_col > MAXCOL) l_col = MAXCOL;
  1355.     if (r_col < 0) r_col = 0;
  1356.     if (r_col > MAXCOL) r_col = MAXCOL;
  1357.     
  1358.     /* if nothing to do, don't bother */
  1359.     if ((r_col == 0) || (l_col == r_col))
  1360.     return;
  1361.     
  1362.     /***** I shouldn't have to put this here! *****/
  1363.     if (termw->screeninvert) {
  1364.     BackPat(qd.black);
  1365.     PenPat(qd.white);
  1366.     TextMode (srcBic);
  1367.     } else {
  1368.     BackPat(qd.white);
  1369.     PenPat(qd.black);
  1370.     TextMode (srcOr);
  1371.     }
  1372.  
  1373.     if ((v < 0) || (v > termw->screensize))
  1374.     printerr("draw_line_w_attrs, v out of range:", v);
  1375.  
  1376.     line_ch = termw->scr[lin];
  1377.     line_at = termw->scr_attrs[lin];
  1378.     lines_attrs = (int) termw->line_attrs[lin];
  1379.     if (lines_attrs != VT_SNGL) {
  1380.     /* double width lines have half as many characters (duh!) */
  1381.     orig_l_col = l_col;
  1382.     l_col /= 2;
  1383.     r_col = (r_col + 1) / 2;    /* round out to next highest */
  1384.     }
  1385.     
  1386.     /*
  1387.      * find the last character that is not a plain space character
  1388.      */
  1389.     sty = 0;    /* the style for normal blank space */
  1390.     cp = line_ch + r_col-1;
  1391.     ap = line_at + r_col-1;
  1392.     for (max = r_col-1; max >= l_col; max--) {
  1393.             /* PWP: we should never see a NUL in the line here */
  1394.     if ((*cp-- != ' ') || (*ap-- != sty))
  1395.         break;
  1396.     
  1397.     }
  1398.     max++;    /* point to one after the last non-space character */
  1399.     if (max > r_col) max = r_col;
  1400.  
  1401.     /*
  1402.      * find the first character that is not a plain space character
  1403.      */
  1404.     sty = 0;    /* the style for normal blank space */
  1405.     cp = line_ch + l_col;
  1406.     ap = line_at + l_col;
  1407.     for (min = l_col; min < max; min++) {
  1408.             /* PWP: we should never see a NUL in the line here */
  1409.     if ((*cp++ != ' ') || (*ap++ != sty))
  1410.         break;
  1411.     }
  1412.  
  1413.     /* If there is anything to erase, erase it */
  1414.     if (must_drawblanks) {
  1415.     if (lines_attrs == VT_SNGL)
  1416.         makerect(termw,&r, v, l_col, 1, r_col-l_col);
  1417.     else
  1418.         makerect(termw,&r, v, (2 * l_col), 1, 2 * (r_col-l_col));
  1419.     EraseRect (&r);
  1420.     }
  1421.         
  1422.     /* A slight speedup -- tell the Mac not to remove this font from RAM */
  1423.     if (!termw->font_is_locked) {
  1424.     SetFontLock(true);
  1425.     termw->font_is_locked = true;
  1426.     }
  1427.         
  1428.  
  1429.     if (lines_attrs == VT_SNGL) {
  1430.     /*
  1431.      * loop through all the characters up to max, looking for the longest
  1432.      * string of characters all of the same style.  Draw them, switch
  1433.      * styles, and repeat until max.
  1434.      */
  1435.     sty = line_at[min];
  1436.     o = min;
  1437.     i = min;
  1438.     while (i <= max) {
  1439.         /* if this style != current style */
  1440.         if ((line_at[i] != sty) || (i == max)) {
  1441.         if (sty != termw->current_style)
  1442.             set_style(termw, sty);
  1443.  
  1444.         if (termw->draw_sing_chars) {
  1445.             /*
  1446.              * We can't just increment o here because we may need
  1447.              * it to correctly draw the inverse video rect (below).
  1448.              */
  1449.             for (j = o, cp = line_ch + o; j < i; j++, cp++) {
  1450.             MOVETOCHAR(j, v);
  1451.             DrawChar((short) (*cp & 0377));
  1452.             }
  1453.         } else {    /* non-blinking */
  1454.             MOVETOCHAR(o, v);
  1455.             DrawText (line_ch, (short) o, (short) i-o);
  1456.                 /* Output this part */
  1457.         }
  1458.         
  1459.         if (sty & VT_INVERT) {
  1460.             makerect(termw,&r, v, o, 1, i-o);
  1461.             InvertRect (&r);
  1462.         }
  1463.         
  1464.         o = i;    /* now left extent == current */
  1465.         sty = line_at[i];    /* new current style */
  1466.         }
  1467.         i++;
  1468.     }
  1469.     } else {
  1470. #ifdef COMMENT_DOES_NOT_WORK
  1471.     RgnHandle clip_rgn = NewRgn();
  1472.     Rect dest_r;
  1473.     GrafPtr oldPort;
  1474.     GrafPort offScreen;
  1475.         
  1476.     /* allocate our off-screen bitmap */
  1477.     GetPort(&oldPort);
  1478.     OpenPort(&offScreen);
  1479.     SetPort(oldPort);
  1480.     
  1481.     /* Make our off-screen bitmap the size of one line */
  1482.     offScreen.portRect.top = 0;
  1483.     offScreen.portRect.left = 0;
  1484.     offScreen.portRect.bottom = termw->lineheight;
  1485.     offScreen.portRect.right = termw->charwidth;
  1486.  
  1487.     /* rowBytes is the size of a row, rounded up to an even number */
  1488.     /* of bytes */
  1489.     offScreen.portBits.rowBytes = (((offScreen.portBits.bounds.right
  1490.             - offScreen.portBits.bounds.left) + 15) >> 4) << 1;
  1491.     
  1492.     /* number of bytes in BitMap is rowBytes * number of rows */
  1493.     /* this calculation must be down with longs */
  1494.     offScreen.portBits.baseAddr = NewPtr((long) offScreen.portBits.rowBytes
  1495.         * (long) (offScreen.portBits.bounds.bottom
  1496.               - offScreen.portBits.bounds.top));
  1497.     
  1498.     if (!offScreen.portBits.baseAddr)    /* we didn't get the memory */
  1499.         return;        /* just forget it */
  1500.  
  1501.     /*
  1502.      * We are drawing double-width (and maybe double height) chars.
  1503.      *
  1504.      * First, draw the line normally, but starting at the
  1505.      * real position of original the original value of l_col.
  1506.      */
  1507.     SetPort (&offScreen);
  1508.     BackPat(qd.white);
  1509.     PenPat(qd.black);
  1510.     TextMode (srcOr);
  1511.     EraseRect(&qd.thePort->portRect);    /* erase just in case */
  1512.  
  1513.     o = 0;
  1514.     cp = line_ch + min;
  1515.     ap = line_at + min;
  1516.     for (i = min; i <= max; i++) {
  1517.  
  1518.         MoveTo ((o * termw->charwidth),
  1519.                 (termw->lineheight - termw->chardescent));
  1520.         DrawChar((short) (*cp & 0377));
  1521.         if (*ap & VT_INVERT) {
  1522.         makerect(termw,&r, v, o, 1, 1);
  1523.         InvertRect (&r);
  1524.         }
  1525.         o++;
  1526.         cp++;
  1527.         ap++;
  1528.     }
  1529.  
  1530.     /* set the output port back to the screen */
  1531.     SetPort(oldPort);
  1532.  
  1533.     /* Next, stretch the characters using a CopyBits() */
  1534.     /* find the clipping region */
  1535.     makerect(termw, &r, v, (2 * l_col), 1, 2 * (r_col-l_col));
  1536.     RectRgn (clip_rgn, &r);
  1537.     FillRgn (clip_rgn, qd.gray);
  1538.     
  1539.     /* compute the source rect (where we just drew characters into) */
  1540.     r = offScreen.portRect;
  1541.     r.right = (max-min+1) * termw->charwidth;
  1542.  
  1543.     /* 
  1544.      * Compute the dest rect.  This also defines how we stretch
  1545.      * the characters out to be double width.
  1546.      */
  1547.     
  1548.     if (lines_attrs == VT_DBLH_T) {
  1549.         makerect(termw, &dest_r, v, ((2 * l_col) + (min - l_col)),
  1550.         2, (2 * (max-min+1)));
  1551.     } else if (lines_attrs == VT_DBLH_B) {
  1552.         makerect(termw, &dest_r, (v-1), ((2 * l_col) + (min - l_col)),
  1553.         2, (2 * (max-min+1)));
  1554.     } else {        /* lines_attrs == VT_DBLW */
  1555.         makerect(termw, &dest_r, v, ((2 * l_col) + (min - l_col)),
  1556.         1, (2 * (max-min+1)));
  1557.     }
  1558.  
  1559.     makerect(termw, &dest_r, v, ((2 * l_col) + (min - l_col)),
  1560.         1, (max-min+1));
  1561.  
  1562.     /* now stretch those bits */
  1563.     CopyBits (&offScreen.portBits, &qd.thePort->portBits,
  1564.           &offScreen.portRect, &dest_r,
  1565.           ((termw->screeninvert) ? notSrcCopy : srcCopy), clip_rgn);
  1566.     
  1567.     /* clean up */
  1568.     DisposeRgn(clip_rgn);
  1569.     ClosePort(&offScreen);
  1570. #endif /* COMMENT_DOES_NOT_WORK */
  1571.  
  1572.     /* draw the double width line as double spaced characters */
  1573.     o = min;
  1574.     cp = line_ch + min;
  1575.     ap = line_at + min;
  1576.     for (i = min; i <= max; i++) {
  1577.         if (*ap != termw->current_style)
  1578.         set_style(termw, *ap);
  1579.         MOVETOCHAR((2 * o), v);
  1580.         DrawChar((short) (*cp & 0377));
  1581.         if (*ap & VT_INVERT) {
  1582.         makerect(termw,&r, v, (2 * o), 1, 2);
  1583.         InvertRect (&r);
  1584.         }
  1585.         o++;
  1586.         cp++;
  1587.         ap++;
  1588.     }
  1589.     }
  1590. }                /* draw_line_w_attrs() */
  1591.  
  1592.  
  1593. /****************************************************************************/
  1594. /****************************************************************************/
  1595. void scroll_term (struct termw *termw)
  1596. {
  1597.     register int new_topline, delta, lin, i;
  1598.     int fl, fc, tl, tc;
  1599.     Rect r;            /* cannot be register */
  1600.  
  1601.     new_topline = termw->screensize - termw->display_totlines + 
  1602.     GetCtlValue (termw->t_vscroll);
  1603.     if ((new_topline > 0) ||
  1604.     (new_topline <  termw->screensize - MAX_SCREENSIZE)) {
  1605.         printerr("BUG: in scroll_term(), new_topline out of range:",
  1606.          new_topline);
  1607.     return;
  1608.     }
  1609.     if ((delta = (termw->display_topline - new_topline)) == 0)
  1610.     return;        /* we didn't move */
  1611.  
  1612.     makerect(termw,&r, 0, 0, termw->screensize, MAXCOL);
  1613.     
  1614.     /* if whole screen */
  1615.     if ((delta >= termw->screensize) || (-delta >= termw->screensize)) {
  1616.         EraseRect(&r);
  1617.     
  1618.         lin = new_topline;            /* new top line */
  1619.     for (i = 0; i < termw->screensize; i++) {
  1620.         draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 0);
  1621.         lin++;
  1622.     }
  1623.     termw->display_topline = new_topline;
  1624.  
  1625.     if (termw->have_selection)
  1626.         invert_text(termw,
  1627.             termw->from_lin,
  1628.             termw->from_col,
  1629.             termw->to_lin,
  1630.             termw->to_col);
  1631.         
  1632.     return;    /* we are done */
  1633.     }
  1634.  
  1635.     /* if we get here, we are not doing the whole screen */
  1636.     ScrollRect (&r, 0, delta * termw->lineheight, dummyRgn);
  1637.  
  1638.     if (delta > 0) {    /* scrolling down (pushing top arrow) */
  1639.         lin = new_topline;            /* new top line */
  1640.     for (i = 0; (i < delta) && (i < termw->screensize); i++) {
  1641.         draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 0);
  1642.         lin++;
  1643.     }
  1644.     termw->display_topline = new_topline;
  1645.  
  1646.     if (termw->have_selection &&
  1647.         (termw->from_lin < termw->display_topline + delta) &&
  1648.         (termw->to_lin >= termw->display_topline)) {
  1649.         if (termw->from_lin < termw->display_topline) {
  1650.         fl = termw->display_topline;
  1651.         fc = 0;
  1652.         } else {
  1653.         fl = termw->from_lin;
  1654.         fc = termw->from_col;
  1655.         }
  1656.         if (termw->to_lin >= termw->display_topline + delta) {
  1657.         tl = termw->display_topline + delta - 1;
  1658.         tc = MAXCOL;
  1659.         } else {
  1660.         tl = termw->to_lin;
  1661.         tc = termw->to_col;
  1662.         }
  1663.         invert_text(termw, fl, fc, tl, tc);
  1664.     }
  1665.     } else {        
  1666.     /* scrolling up (pushing bottom arrow) */
  1667.     /* one past old bottom line*/
  1668.         lin = termw->display_topline + termw->screensize;
  1669.     /*********** PWP: delta is negative here ****************/
  1670.     i = termw->screensize + delta;
  1671.     if (i < 0) i = 0;    /* bounds */
  1672.     while (i < termw->screensize)
  1673.         draw_line_w_attrs(termw, lin++, i++, 0, MAXCOL, 0);
  1674.     termw->display_topline = new_topline;
  1675.  
  1676.     if (termw->have_selection &&
  1677.         (termw->from_lin <
  1678.          (termw->display_topline + termw->screensize)) &&
  1679.         (termw->to_lin >=
  1680.          (termw->display_topline + termw->screensize + delta))) {
  1681.  
  1682.         /*
  1683.          * If selection is partially off the top,
  1684.          * clip display of region at top
  1685.          */
  1686.         if (termw->from_lin <
  1687.         termw->display_topline + termw->screensize + delta) {
  1688.         fl = termw->display_topline + termw->screensize + delta;
  1689.         fc = 0;
  1690.         } else {
  1691.         fl = termw->from_lin;
  1692.         fc = termw->from_col;
  1693.         }
  1694.  
  1695.         /*
  1696.          * If selection is partially off the top,
  1697.          * clip display of region at top.
  1698.          */
  1699.         if (termw->to_lin >= termw->display_topline + termw->screensize) {
  1700.         tl = termw->display_topline + termw->screensize - 1;
  1701.         tc = MAXCOL;
  1702.         } else {
  1703.         tl = termw->to_lin;
  1704.         tc = termw->to_col;
  1705.         }
  1706.  
  1707.         invert_text(termw, fl, fc, tl, tc);
  1708.     }
  1709.     }
  1710. }
  1711.  
  1712. static pascal void
  1713. doscroll (WHICHCONTROL, THECODE)
  1714. ControlHandle WHICHCONTROL;
  1715. short THECODE;
  1716. {
  1717.     register int amount = 0, val, max;
  1718.     struct termw *termw;
  1719.     
  1720.     if (FrontWindow() == ctermw->window)
  1721.         termw = ctermw    ;
  1722.     else if (FrontWindow() == ttermw->window)
  1723.         termw = ttermw    ;
  1724.     else
  1725.         return;
  1726.  
  1727.     if (THECODE == inUpButton)
  1728.     amount = -1;
  1729.     if (THECODE == inDownButton)
  1730.     amount = 1;
  1731.     if (amount == 0)
  1732.     return;
  1733.     val = GetCtlValue (WHICHCONTROL) + amount;
  1734.     max = GetCtlMax (WHICHCONTROL);
  1735.     if ((val >= 0) && (val <= max)) {
  1736.     SetCtlValue (WHICHCONTROL, val);
  1737.     scroll_term(termw);
  1738.     }
  1739. }                /* doscroll */
  1740.  
  1741.  
  1742. /****************************************************************************/
  1743. /* we move the displayed region to the bottom when we recieve characters */
  1744. /****************************************************************************/
  1745.  
  1746. screen_to_bottom (struct termw *termw)
  1747. {
  1748.     if (termw->display_topline != toplin) {
  1749.     SetCtlValue (termw->t_vscroll, 
  1750.              termw->display_totlines - termw->screensize);
  1751.     scroll_term(termw);
  1752.     }
  1753. }
  1754.  
  1755. /****************************************************************************/
  1756. /* update_vscroll - adjust the scaling of the vertical scroll bar, or  */
  1757. /*                      disable it if we havn't saved anything back yet */
  1758. /****************************************************************************/
  1759. update_vscroll (struct termw *termw)
  1760. {
  1761.     short s;
  1762.     
  1763.     s = termw->display_totlines-termw->screensize;
  1764.  
  1765.     if (s != GetCtlMax (termw->t_vscroll))
  1766.     SetCtlMax (termw->t_vscroll, s);
  1767.  
  1768.     if (s != GetCtlValue (termw->t_vscroll))
  1769.     SetCtlValue (termw->t_vscroll, s);
  1770.  
  1771.     if (termw->in_front && termw->display_totlines > termw->screensize) {
  1772.     if (termw->scroll_drawn != 1) {
  1773.         HiliteControl (termw->t_vscroll, 0);
  1774.         termw->scroll_drawn = 1;
  1775.     }
  1776.     } else {
  1777.     if (termw->scroll_drawn != 0) {
  1778.         HiliteControl (termw->t_vscroll, 255);
  1779.         termw->scroll_drawn = 0;
  1780.     }
  1781.     }
  1782. }
  1783.  
  1784. /****************************************************************************/
  1785. /****************************************************************************/
  1786. void t_pagescroll (struct termw *termw, int code, int amount, 
  1787.            ControlHandle ctrlh)
  1788. {
  1789.     Point myPt;
  1790.     register int val, max;
  1791.  
  1792.     max = GetCtlMax (ctrlh);
  1793.     val = GetCtlValue (ctrlh);
  1794.     
  1795.     do {
  1796.     GetMouse (&myPt);
  1797.     if (TestControl (ctrlh, myPt) != code)
  1798.         continue;
  1799.     
  1800.     val += amount;
  1801.     if (val < 0)
  1802.         val = 0;
  1803.     if (val > max)
  1804.         val = max;
  1805.     SetCtlValue (ctrlh,  val);
  1806.     scroll_term(termw);
  1807.     } while (StillDown ());
  1808. }                /* pagescroll */
  1809.  
  1810.  
  1811. termmouse (struct termw *termw, EventRecord *evt)
  1812. {
  1813.     int actrlcode;
  1814.     ControlHandle acontrol;
  1815.     GrafPtr savePort;
  1816.     
  1817.     GetPort (&savePort);    /* save the current port */
  1818.     SetPort (termw->window);
  1819.  
  1820.     GlobalToLocal (&evt->where);/* convert to local */
  1821.     if (termw->mouse_arrows || (evt->modifiers & optionKey)) {
  1822.     /* In terminal content? */
  1823.     if (PtInRect (evt->where, &termw->ScreenRect)) {
  1824.         mouse_cursor_move(termw, evt);        
  1825.         SetPort (savePort);        /* restore previous port */
  1826.         return;            /* yes, do mouse stuff */
  1827.     }
  1828.     }
  1829.     cursor_erase(termw);
  1830.     actrlcode = FindControl (evt->where, termw->window, &acontrol);
  1831.     switch (actrlcode) {    
  1832.       case inUpButton:
  1833.       case inDownButton:
  1834.     (void) TrackControl (acontrol, evt->where, (ProcPtr) doscroll);
  1835.     break;
  1836.  
  1837.       case inPageUp:
  1838.     t_pagescroll (termw, actrlcode, -(termw->screensize/2), acontrol);
  1839.     break;
  1840.  
  1841.       case inPageDown:
  1842.     t_pagescroll (termw, actrlcode, (termw->screensize/2), acontrol);
  1843.     break;
  1844.  
  1845.       case inThumb:
  1846.     (void) TrackControl (acontrol, evt->where, (ProcPtr) NIL);
  1847.     scroll_term(termw);
  1848.     break;
  1849.     
  1850.       case 0:        /* in the window content itself */
  1851.         /* $$$ SHOULD DO SOMETHING ABOUT DOUBLE CLICKS HERE!! */
  1852.     mouse_region_select(termw, evt);
  1853.     break;
  1854.     }
  1855.     /* MOVETOCHAR(termw->curcol, termw->curlin - termw->display_topline); */
  1856.     cursor_draw(termw);
  1857.     SetPort (savePort);        /* restore previous port */
  1858. }
  1859.  
  1860.  
  1861. /* 
  1862.  * dir is 'A' (up), 'B' (down), 'C' (right), or 'D' (left) 
  1863.  */
  1864. void do_arrow(struct termw *termw, unsigned char dir)
  1865. {
  1866.     OutputChar(termw, '\033');        /* ESC */
  1867.     if (termw->curskey_mode)
  1868.         OutputChar(termw, 'O');    /* SS3 */
  1869.     else
  1870.         OutputChar(termw, '[');    /* CSI */
  1871.     OutputChar(termw, dir);
  1872. }
  1873.  
  1874. /* char to send is n + ',' */
  1875. void do_keypad (struct termw *termw, int n)
  1876. {
  1877.     if (termw->appl_mode) {
  1878.         OutputChar(termw, '\033');        /* ESC */
  1879.         OutputChar(termw, 'O');    /* SS3 */
  1880.     OutputChar(termw, (unsigned char) n + 'l');
  1881.     } else {
  1882.         OutputChar(termw, (unsigned char) n + ',');    /* normal digit or glyph */
  1883.     }
  1884. }
  1885.  
  1886. /* pf1 == 0 ... pf4 == 3 */
  1887. void do_pfkey(struct termw *termw, int n)
  1888. {
  1889.     OutputChar(termw, '\033');        /* ESC */
  1890.     OutputChar(termw, 'O');    /* SS3 */
  1891.     OutputChar(termw, (unsigned char) n + 'P');
  1892. }
  1893.  
  1894. void do_keyenter(struct termw *termw)
  1895. {
  1896.     if (termw->appl_mode) {
  1897.         OutputChar(termw, '\033');        /* ESC */
  1898.         OutputChar(termw, 'O');    /* SS3 */
  1899.     OutputChar(termw, 'M');
  1900.     } else {
  1901.         OutputChar(termw, '\015');
  1902.     }
  1903. }
  1904.  
  1905. void mouse_cursor_move (struct termw *termw, EventRecord *evt)
  1906. {
  1907.     int mouselin;
  1908.     int mousecol;
  1909.     int tempcol;
  1910.     int templin;
  1911.     int i;
  1912.     Point MousePt;
  1913.  
  1914.     MousePt = evt->where;
  1915.     mouselin = (MousePt.v - TOPMARGIN) / termw->lineheight;
  1916.     mousecol = (MousePt.h - LEFTMARGIN + termw->charwidth/2) / 
  1917.     termw->charwidth;
  1918.     tempcol = termw->curcol;
  1919.     templin = termw->curlin;
  1920.  
  1921.     if (mousecol < tempcol)
  1922.     for (i = tempcol; i > mousecol; i--) {
  1923.         do_arrow (termw, leftARROW);
  1924.         waitasec (termw);
  1925.         /* If tabs are used, we may go too far, so end loop */
  1926.         if (termw->curcol <= mousecol)
  1927.         i = mousecol;
  1928.     }
  1929.  
  1930.     if (mouselin < templin)
  1931.     for (i = templin; i > mouselin; i--) {
  1932.         do_arrow (termw, UPARROW);
  1933.         waitasec (termw);
  1934.     }
  1935.  
  1936.     else if (mouselin > templin)
  1937.     for (i = templin; i < mouselin; i++) {
  1938.         do_arrow (termw, DOWNARROW);
  1939.         waitasec (termw);
  1940.     }
  1941.  
  1942.     if (termw->curlin == mouselin)
  1943.     tempcol = termw->curcol;    /* for short lines */
  1944.  
  1945.     if (tempcol < mousecol)
  1946.     for (i = tempcol; i < mousecol; i++) {
  1947.         do_arrow (termw, rightARROW);
  1948.         waitasec (termw);
  1949.         /* If tabs are used, we may go too far, so end loop */
  1950.         if (termw->curcol >= mousecol)
  1951.         i = mousecol;
  1952.     }
  1953. }                /* mouse_cursor_move */
  1954.  
  1955. void invert_text(struct termw *termw, 
  1956.             int from_lin, 
  1957.             int from_col, 
  1958.             int to_lin, 
  1959.             int to_col)
  1960. {
  1961.     int t;
  1962.     
  1963.     if (from_lin > to_lin) {        /* make from < to */
  1964.         t = to_lin;
  1965.     to_lin = from_lin;
  1966.     from_lin = t;
  1967.         t = to_col;
  1968.     to_col = from_col;
  1969.     from_col = t;
  1970.     }
  1971.     
  1972.     /* if we are doing double width chars, the columns are twice as wide */
  1973.     if (termw->line_attrs[from_lin] != VT_SNGL)
  1974.     from_col *= 2;
  1975.     if (termw->line_attrs[to_lin] != VT_SNGL)
  1976.     to_col *= 2;
  1977.  
  1978.     from_lin -= termw->display_topline;    /* convert to screen coords */
  1979.     if (from_lin < 0) {
  1980.     from_lin = 0;
  1981.     from_col = 0;
  1982.     }
  1983.     
  1984.     /* if down out of sight, forget it */
  1985.     if (from_lin >= termw->screensize)
  1986.     return;
  1987.     
  1988.     to_lin -= termw->display_topline;    /* convert to screen coords */
  1989.     
  1990.     if (to_lin < 0)            /* if up out of sight, forget it */
  1991.     return;
  1992.     
  1993.     if (to_lin >= termw->screensize) {
  1994.     to_lin = termw->screensize-1;
  1995.     to_col = MAXCOL;
  1996.     }
  1997.  
  1998.     if (from_lin == to_lin) {        /* if only one line */
  1999.     if (from_col > to_col) {
  2000.             t = to_col;
  2001.         to_col = from_col;
  2002.         from_col = t;
  2003.     }
  2004.                   
  2005.     if (from_col != to_col)     /* then invert the characters in between */
  2006.         invertchars(termw, from_lin, from_col, 1, to_col - from_col);
  2007.     } else {
  2008.     if (from_col < MAXCOL)
  2009.         invertchars(termw, from_lin, from_col, 1, MAXCOL - from_col);
  2010.     t = to_lin - from_lin - 1;
  2011.     if (t > 0)
  2012.         invertchars(termw, from_lin+1, 0, t, MAXCOL);
  2013.     if (to_col > 0)
  2014.         invertchars(termw, to_lin, 0, 1, to_col);
  2015.     }
  2016. }
  2017.  
  2018.  
  2019. int typeof_char(unsigned char c)
  2020. {
  2021.     if ((c == ' ') || (c == '\240'))
  2022.         return (0);            /* whitespace char */
  2023.  
  2024.     if (((c >= '0') && (c <= '9'))
  2025.         || ((c >= 'A') && (c <= 'Z'))
  2026.         || ((c >= 'a') && (c <= 'z'))
  2027.         || ((c >= '\300') && (c <= '\377') && (c != '\327') && (c != '\367'))
  2028.         || ((c >= '\271') && (c <= '\276') && (c != '\273'))
  2029.         || (c == '\262') || (c == '\263') || (c == '\252'))
  2030.     return (1);            /* alpha-numeric char */
  2031.  
  2032.     return (2);                /* printing, non-alphanum char */
  2033. }
  2034.  
  2035.  
  2036. int all_spaces (struct termw *termw, register int r, register int c)
  2037. {
  2038.     register int i;
  2039.     
  2040.     for (i = c; i < line_maxcol(termw, r); i++)
  2041.     if ((termw->scr[r][i] != ' ')
  2042.         || (termw->scr_attrs[r][i] != 0))
  2043.         return (0);            /* found a non-space */
  2044.  
  2045.     return (1);                /* everything was spaces */
  2046. }
  2047.  
  2048.  
  2049. void point_to_mouse_low_high (struct termw *termw, 
  2050.              Point *MousePt_p,
  2051.              int n_clicks,
  2052.              int *mouselin_p,
  2053.              int *mousecol_p,
  2054.              int *mousecol_lp,
  2055.              int *mousecol_hp)
  2056. {
  2057.     int real_lin, real_col;
  2058.     int ch_type, ch_attr;
  2059.     int i;
  2060.     
  2061.     real_lin = (MousePt_p->v-TOPMARGIN) / termw->lineheight + 
  2062.     termw->display_topline;
  2063.     if (real_lin < termw->display_topline)
  2064.     real_lin = termw->display_topline;
  2065.     if (real_lin >= termw->display_topline + termw->screensize)
  2066.     real_lin = termw->display_topline + termw->screensize-1;
  2067.  
  2068.     *mouselin_p = real_lin;
  2069.     
  2070.     real_col = (MousePt_p->h - LEFTMARGIN + termw->charwidth/2) / 
  2071.     termw->charwidth;
  2072.     if (real_col < 0) real_col = 0;
  2073.     if (real_col > MAXCOL)        /* this is a real, not virtual, column */
  2074.         real_col = MAXCOL;
  2075.  
  2076.     /* if on a double-width line, all columns are twice as wide */
  2077.     if (termw->line_attrs[real_lin] != VT_SNGL)
  2078.     real_col /= 2;
  2079.     
  2080.     /*
  2081.      * We spoof things a bit here -- if the rest of the line is all blanks,
  2082.      * then we treat it as a single character (CRLF, really), and pretend
  2083.      * that the user clicked the mouse in the first blank character after all
  2084.      * text.
  2085.      */
  2086.     if (all_spaces(termw,real_lin, real_col))
  2087.     {
  2088.         for (i = real_col; i >= 0; i--)
  2089.         if ((termw->scr[real_lin][i] != ' ')
  2090.             || (termw->scr_attrs[real_lin][i] != 0))
  2091.         break;
  2092.     real_col = i+1;
  2093.     if (real_col < 0) real_col = 0;
  2094.     if (real_col > line_maxcol(termw, real_lin))
  2095.         real_col = line_maxcol(termw, real_lin);
  2096.     }
  2097.     
  2098.     *mousecol_p = real_col;
  2099.  
  2100.     if (n_clicks == 0)        /* if a SINGLE click */
  2101.     {
  2102.         *mousecol_lp = real_col;
  2103.     *mousecol_hp = real_col;
  2104.     }
  2105.     else if (n_clicks == 1)    /* if a DOUBLE click */
  2106.     {
  2107.     ch_type = typeof_char (termw->scr[real_lin][real_col]);
  2108.     ch_attr = termw->scr_attrs[real_lin][real_col];
  2109.     for (i = real_col-1; i >= 0; i--)
  2110.       /* if a different type */
  2111.         if ((typeof_char (termw->scr[real_lin][i]) != ch_type)
  2112.         /* or colored different */
  2113.             || (termw->scr_attrs[real_lin][i] != ch_attr))
  2114.           /* then it isn't the same kind of char */
  2115.           break;            
  2116.     *mousecol_lp = i+1;
  2117.     for (i = real_col+1; i < line_maxcol(termw, real_lin); i++)
  2118.       /* if a different type */
  2119.         if ((typeof_char (termw->scr[real_lin][i]) != ch_type)
  2120.         /* or colored different */
  2121.             || (termw->scr_attrs[real_lin][i] != ch_attr)) 
  2122.           /* then it isn't the same kind of char */
  2123.           break;
  2124.     *mousecol_hp = i;
  2125.     }
  2126.     else                /* a TRIPLE click */
  2127.     {
  2128.         *mousecol_lp = 0;
  2129.     *mousecol_hp = line_maxcol(termw, real_lin);
  2130.     }
  2131. }
  2132.  
  2133.  
  2134. void mouse_region_select (struct termw *termw, EventRecord *evt)
  2135. {
  2136.     int mouselin;
  2137.     int mousecol_l, mousecol_h, real_mousecol;
  2138.     int i, shift, sval, smax;
  2139.     int old_from_lin, old_from_col, old_to_lin, old_to_col;
  2140.     Point MousePt;
  2141.     /* used for double-click determination */
  2142.     static Point prev_mouse_point = {0, 0};
  2143.     static long prev_mouse_up = 0L;
  2144.     static int n_clicks_here = 0;
  2145.  
  2146.     MousePt = evt->where;
  2147.  
  2148.     /* if no selection, then a shift drag is just a drag */
  2149.     if (termw->have_selection)
  2150.     shift = (evt->modifiers) & shiftKey;
  2151.     else
  2152.     shift = 0;
  2153.  
  2154.     if (((evt->when - prev_mouse_up) <= GetDblTime())
  2155.         && (ABS(MousePt.v - prev_mouse_point.v) < termw->lineheight)
  2156.     && (ABS(MousePt.h - prev_mouse_point.h) < termw->charwidth))
  2157.     n_clicks_here = (n_clicks_here + 1) % 3;
  2158.     else
  2159.         n_clicks_here = 0;        /* just one click */
  2160.  
  2161.     prev_mouse_point = MousePt;            /* save for next time */
  2162.     prev_mouse_up = TickCount ();        /* save when the mouse went up */
  2163.  
  2164.     /* if not adding to region, remove old one */
  2165.     if (!shift && termw->have_selection)
  2166.         invert_text(termw,
  2167.             termw->from_lin,
  2168.             termw->from_col,
  2169.             termw->to_lin,
  2170.             termw->to_col);
  2171.  
  2172.  
  2173.     point_to_mouse_low_high(termw,&MousePt, n_clicks_here, &mouselin,
  2174.                      &real_mousecol, &mousecol_l, &mousecol_h);
  2175.  
  2176.     if (shift) {
  2177.     /*
  2178.      * Swap from_* and to_* if closer to from.  This sets the further-away
  2179.      * side as the anchor, and the closer one as the part we are changing.
  2180.      *
  2181.      * We aren't taking into account any double width lines here, but that
  2182.      * should be OK anyway (I hope)
  2183.      */
  2184.     if (ABS((MAXCOL * termw->from_lin + termw->from_col) -
  2185.         (MAXCOL * mouselin + real_mousecol)) <
  2186.         ABS((MAXCOL * termw->to_lin + termw->to_col)
  2187.         - (MAXCOL * mouselin + real_mousecol))) {
  2188.             i = termw->to_lin;
  2189.         termw->to_lin = termw->from_lin;
  2190.         termw->from_lin = i;
  2191.             i = termw->to_col;
  2192.         termw->to_col = termw->from_col;
  2193.         termw->from_col = i;
  2194.     }
  2195.     } else {
  2196.     termw->from_lin = mouselin;
  2197.     termw->from_col = mousecol_l;
  2198.     termw->to_lin = mouselin;
  2199.     termw->to_col = mousecol_h;
  2200.     
  2201.     /* Select the text if a double or triple click. */
  2202.     if (termw->from_col != termw->to_col)
  2203.             invert_text(termw,
  2204.             termw->from_lin,
  2205.             termw->from_col,
  2206.             termw->to_lin,
  2207.             termw->to_col);
  2208.     }
  2209.     /* save in case we have to swap which point is the anchor */
  2210.     old_from_lin = termw->from_lin;
  2211.     old_from_col = termw->from_col;
  2212.     old_to_lin = termw->to_lin;
  2213.     old_to_col = termw->to_col;
  2214.     
  2215.     while (StillDown()) {
  2216.     GetMouse(&MousePt);
  2217.     point_to_mouse_low_high(termw,&MousePt, n_clicks_here, &mouselin,
  2218.                      &real_mousecol, &mousecol_l, &mousecol_h);
  2219.  
  2220.     /*
  2221.      * If above or below screen, auto-scroll the slider and select more.
  2222.      */
  2223.     
  2224.     if (mouselin < termw->display_topline) {
  2225.         sval = GetCtlValue (termw->t_vscroll) - 1;
  2226.         smax = GetCtlMax (termw->t_vscroll);
  2227.         if ((sval >= 0) && (sval <= smax)) {
  2228.         SetCtlValue (termw->t_vscroll, sval);
  2229.         scroll_term(termw);
  2230.         }
  2231.         mouselin = termw->display_topline;
  2232.         real_mousecol = 0;
  2233.  
  2234.     } else if (mouselin >= termw->display_topline + termw->screensize) {
  2235.         sval = GetCtlValue (termw->t_vscroll) + 1;
  2236.         smax = GetCtlMax (termw->t_vscroll);
  2237.         if ((sval >= 0) && (sval <= smax)) {
  2238.         SetCtlValue (termw->t_vscroll, sval);
  2239.         scroll_term(termw);
  2240.         }
  2241.         mouselin = termw->display_topline + termw->screensize-1;
  2242.         real_mousecol = line_maxcol(termw, mouselin);
  2243.     }
  2244.     
  2245.     /*
  2246.      * If we are above the anchor, then the "interesting" side of the 
  2247.      * click extent is mousecol_l, else it is mousecol_h.
  2248.      *
  2249.      * Again, we are not taking into account any intermediate double-width
  2250.      * lines, but hopefully that's OK.
  2251.      */
  2252.     if ((MAXCOL * termw->from_lin + termw->from_col) > 
  2253.         (MAXCOL * mouselin + real_mousecol))
  2254.     {
  2255.         i = mousecol_l;        /* "above" the anchor point */
  2256.  
  2257.         /* but if we were below the anchor, restore and swap */
  2258.         if ((MAXCOL * termw->from_lin + termw->from_col) < 
  2259.         (MAXCOL * termw->to_lin + termw->to_col))
  2260.         {
  2261.         /* Unselect current text. */
  2262.          invert_text(termw, termw->from_lin, termw->from_col, 
  2263.                 termw->to_lin, termw->to_col);
  2264.  
  2265.         termw->from_lin = old_to_lin;
  2266.         termw->from_col = old_to_col;
  2267.         termw->to_lin = old_from_lin;
  2268.         termw->to_col = old_from_col;
  2269.         
  2270.         /* Reselect new (old) text. */
  2271.          invert_text(termw, termw->from_lin, termw->from_col, 
  2272.                 termw->to_lin, termw->to_col);
  2273.         }
  2274.     } else {
  2275.         i = mousecol_h;        /* "below" the anchor point */
  2276.  
  2277.         /* but if we were above the anchor, restore and swap */
  2278.         if ((MAXCOL * termw->from_lin + termw->from_col) > 
  2279.         (MAXCOL * termw->to_lin + termw->to_col))
  2280.         {
  2281.         /* Unselect current text. */
  2282.          invert_text(termw, termw->from_lin, termw->from_col, 
  2283.                 termw->to_lin, termw->to_col);
  2284.  
  2285.         termw->from_lin = old_from_lin;
  2286.         termw->from_col = old_from_col;
  2287.         termw->to_lin = old_to_lin;
  2288.         termw->to_col = old_to_col;
  2289.         
  2290.         /* Reselect new (old) text. */
  2291.          invert_text(termw, termw->from_lin, termw->from_col, 
  2292.                 termw->to_lin, termw->to_col);
  2293.         }
  2294.     }
  2295.         
  2296.     
  2297.     /*
  2298.      * If any new text was selected, invert it.
  2299.      */
  2300.     if ((i != termw->to_col) || (mouselin != termw->to_lin)) {
  2301.         invert_text(termw, termw->to_lin, termw->to_col, mouselin, i);
  2302.         termw->to_lin = mouselin;
  2303.         termw->to_col = i;
  2304.     }
  2305.     }
  2306.     
  2307.     /* make from < to */    
  2308.     if ((MAXCOL * termw->from_lin + termw->from_col) > 
  2309.     (MAXCOL * termw->to_lin + termw->to_col)) {
  2310.         i = termw->to_lin;
  2311.     termw->to_lin = termw->from_lin;
  2312.     termw->from_lin = i;
  2313.         i = termw->to_col;
  2314.     termw->to_col = termw->from_col;
  2315.     termw->from_col = i;
  2316.     }
  2317.     
  2318.     if ((termw->from_lin != termw->to_lin) ||
  2319.     (termw->from_col != termw->to_col))
  2320.     termw->have_selection = TRUE;
  2321.     else
  2322.     termw->have_selection = FALSE;
  2323.     
  2324.     /*
  2325.      * If the mouse wasn't down long enough to be a drag, time double click
  2326.      * from the mouse UP.
  2327.      */
  2328.     if (((TickCount () - prev_mouse_up) <= GetDblTime())
  2329.         && (ABS(MousePt.v - prev_mouse_point.v) < termw->lineheight)
  2330.     && (ABS(MousePt.h - prev_mouse_point.h) < termw->charwidth)) {
  2331.     prev_mouse_up = TickCount ();    /* save when the mouse went up */
  2332.     }
  2333. }
  2334.  
  2335. /* (PWP) if the selection is within [tlin,blin], then remove it */
  2336.  
  2337. void maybe_nuke_selection (struct termw *termw, int tlin, int blin)
  2338. {
  2339.     int my_to_lin;
  2340.  
  2341.     if (!termw->have_selection)
  2342.     return;
  2343.  
  2344.     my_to_lin = termw->to_lin;
  2345.     if ((termw->to_col == 0) && (termw->from_lin != termw->to_lin))
  2346.         my_to_lin--;
  2347.  
  2348.     if (!(((tlin < termw->from_lin) && (blin < termw->from_lin))
  2349.       || ((tlin > my_to_lin) && (blin > my_to_lin))) ) {
  2350.     termw->have_selection = FALSE;
  2351.     invert_text(termw,
  2352.             termw->from_lin,
  2353.             termw->from_col,
  2354.             termw->to_lin,
  2355.             termw->to_col);
  2356.     }
  2357. }
  2358.  
  2359. /*
  2360.  * Copy the current selction to the (internal) clipboard.
  2361.  *
  2362.  * This is an external, but we don't have to save the GrafPort
  2363.  * because we don't do anything to the screen.
  2364.  */
  2365. scr_copy (struct termw *termw)
  2366. {
  2367.     int lin, i, rcol;
  2368.     long sz;
  2369.     char *dp;
  2370.     ScrapStuff *pss;
  2371.     
  2372.     if (myclip_h == NIL) {
  2373.     printerr("scr_copy: clip handle not allocated", 0);
  2374.     return;
  2375.     }
  2376.     
  2377.     if (termw->have_selection) {
  2378.     /****** find out how big the text to copy is ******/
  2379.         if (termw->from_lin == termw->to_lin) {
  2380.         /*
  2381.          * If we are copying to the end of line, we should really only copy
  2382.          * a CR instead of all those trailing blanks.  So we must find out
  2383.          * where the last real character is.
  2384.          */
  2385.         if (termw->to_col >= line_maxcol(termw, termw->to_lin)) {
  2386.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2387.             /* last */
  2388.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2389.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2390.             break;
  2391.         } else {
  2392.             rcol = termw->to_col;
  2393.         }
  2394.         sz = rcol - termw->from_col + 1;
  2395.     } else {
  2396.         for (rcol = line_maxcol(termw, termw->from_lin);
  2397.              rcol > termw->from_col; rcol--)    /* first */
  2398.         if ((termw->scr[termw->from_lin][rcol-1] != ' ')
  2399.             || (termw->scr_attrs[termw->from_lin][rcol-1] != 0))
  2400.             break;
  2401.         /* chars plus one for the termw->newline */
  2402.         sz = rcol - termw->from_col + 1;
  2403.  
  2404.         /* in between */
  2405.         for (lin = termw->from_lin+1; lin < termw->to_lin; lin++) {
  2406.         for (rcol = line_maxcol(termw, lin); rcol > 0; rcol--)
  2407.             if ((termw->scr[lin][rcol-1] != ' ')
  2408.             || (termw->scr_attrs[lin][rcol-1] != 0))
  2409.             break;
  2410.         sz += rcol + 1;    /* chars plus one for the termw->newline */
  2411.         }
  2412.  
  2413.         if (termw->to_col >= line_maxcol(termw, termw->to_lin)) {
  2414.             /***** find the last real character *****/
  2415.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2416.             /* last */
  2417.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2418.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2419.             break;
  2420.         } else {
  2421.         rcol = termw->to_col;
  2422.         }
  2423.         sz += rcol;        /* chars */
  2424.         if (termw->to_col >= line_maxcol(termw, termw->to_lin))
  2425.             sz++;
  2426.     }
  2427.     
  2428.     /***** Reality Check *****/
  2429.     if (sz > 8192) {
  2430.         printerr("Too big to copy: ", sz);
  2431.         return;
  2432.     }
  2433.         
  2434.     /****** allocate and lock a buffer for the text ******/
  2435.     if (sz > GetHandleSize ((Handle) myclip_h)) {
  2436.         HUnlock((Handle) myclip_h);
  2437.         /* $$$ this may fail, but we have no way of knowing. */
  2438.         /* (in assembler, this will return a result, but the pascal */
  2439.         /*  version is a PROCEDURE, so we get zilch.  If this fails */
  2440.         /*  we will probably crash the Mac...) */
  2441.         SetHandleSize((Handle) myclip_h, sz);
  2442.     }
  2443.     HLock((Handle) myclip_h);
  2444.     dp = *myclip_h;
  2445.     
  2446.     /****** copy the characters over to the clip ******/
  2447.         if (termw->from_lin == termw->to_lin) {
  2448.         if (termw->to_col >= line_maxcol(termw, termw->to_lin)) {
  2449.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2450.             /* last */
  2451.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2452.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2453.             break;
  2454.         } else {
  2455.             rcol = termw->to_col;
  2456.         }
  2457.         for (i = termw->from_col; i < rcol; i++)
  2458.             *dp++ = termw->scr[termw->from_lin][i];
  2459.         if (termw->to_col >= line_maxcol(termw, termw->to_lin))
  2460.             *dp++ = CR;        /* add the return */
  2461.     } else {
  2462.         /* trim off spaces */
  2463.         for (rcol = line_maxcol(termw, termw->from_lin);
  2464.          rcol > termw->from_col; rcol--)    /* first */
  2465.         if ((termw->scr[termw->from_lin][rcol-1] != ' ')
  2466.             || (termw->scr_attrs[termw->from_lin][rcol-1] != 0))
  2467.             break;
  2468.         for (i = termw->from_col; i < rcol; i++)
  2469.         *dp++ = termw->scr[termw->from_lin][i];
  2470.         *dp++ = CR;
  2471.  
  2472.         /* in between */
  2473.         for (lin = termw->from_lin+1; lin < termw->to_lin; lin++) {
  2474.         for (rcol = line_maxcol(termw, lin); rcol > 0; rcol--)
  2475.             if ((termw->scr[lin][rcol-1] != ' ')
  2476.             || (termw->scr_attrs[lin][rcol-1] != 0))
  2477.             break;
  2478.         for (i = 0; i < rcol; i++)
  2479.             *dp++ = termw->scr[lin][i];
  2480.         *dp++ = CR;
  2481.         }
  2482.  
  2483.         if (termw->to_col == line_maxcol(termw, termw->to_lin)) {
  2484.         for (rcol = line_maxcol(termw, termw->to_lin); rcol>0; rcol--)
  2485.             /* last */
  2486.             if ((termw->scr[termw->to_lin][rcol-1] != ' ')
  2487.             || (termw->scr_attrs[termw->to_lin][rcol-1] != 0))
  2488.             break;
  2489.         } else {
  2490.         rcol = termw->to_col;
  2491.         }
  2492.         for (i = 0; i < rcol; i++)
  2493.         *dp++ = termw->scr[termw->to_lin][i];
  2494.         if (termw->to_col >= line_maxcol(termw, termw->to_lin))
  2495.         *dp++ = CR;
  2496.     }
  2497.     myclip_size = (dp - *myclip_h);
  2498.  
  2499.     /****** check to make sure we didn't overflow the clipboard ******/
  2500.     if (myclip_size > sz)
  2501.         macfatal ("Overflow! myclip_size - sz ==",
  2502.             myclip_size - sz);
  2503.  
  2504.  
  2505.     /****** Now copy our internal clipboard to the Macintosh one *****/
  2506.     /*
  2507.      * $$$ at this point we really should allocate a second buffer,
  2508.      * and copy the characters of our buffer into it, converting them
  2509.      * from whatever ISO set we are displaying with to the Mac char set.
  2510.      */
  2511.     ZeroScrap();
  2512.     if (PutScrap(myclip_size, 'TEXT', *myclip_h) != noErr)
  2513.         printerr("Couldn't PutScrap", 0);        
  2514.     
  2515.     pss = InfoScrap();
  2516.     my_scrapcount = pss->scrapCount;    /* save this to see if the user */
  2517.                         /* cuts/copies outside of us */
  2518.     
  2519.     /****** We are done.  Unlock the handle ******/
  2520.     HUnlock((Handle) myclip_h);
  2521.     } else {
  2522.     SysBeep(3);
  2523.     }
  2524. }
  2525.  
  2526. /*
  2527.  * Paste the clipboard into the terminal, by "typing" it in.
  2528.  *
  2529.  * This also is an external, but we don't have to save the GrafPort
  2530.  * because the only time we do anything to the screen, it's through
  2531.  * inpchars(), which saves the GrafPort itself.
  2532.  */
  2533. scr_paste (struct termw *termw)
  2534. {
  2535.     char *cp, *endp;
  2536.     char **h;
  2537.     long l, o;
  2538.     ScrapStuff *pss;
  2539.  
  2540.     pss = InfoScrap();
  2541.     if (my_scrapcount == pss->scrapCount) {
  2542.         /* if this is still the same scrap that we made */
  2543.     if (myclip_size > 0) {
  2544.         HLock((Handle) myclip_h);
  2545.         cp = *myclip_h;
  2546.         endp = cp + myclip_size;
  2547.         for (; cp < endp; cp++) {
  2548.         OutputChar(termw, *cp);
  2549.         if (*cp == CR)
  2550.             waitasec (termw);
  2551.         }
  2552.         HUnlock((Handle) myclip_h);
  2553.     } else {
  2554.         SysBeep(3);
  2555.     }
  2556.     } else {    /* we have to get the TEXT scrap from the clipboard */
  2557.     h = NewHandle(0);
  2558.     l = GetScrap(h, 'TEXT', &o);
  2559.     if (l <= 0) {
  2560.         SysBeep(3);
  2561.     } else {
  2562.         HLock((Handle) h);
  2563.         cp = *h;
  2564.         endp = cp + l;
  2565.         for (; cp < endp; cp++) {
  2566.             /* $$$ Should convert *cp to whatever ISO font we are typing */
  2567.         OutputChar(termw, *cp);
  2568.         if (*cp == CR)
  2569.             waitasec (termw);
  2570.         }
  2571.         HUnlock((Handle) h);
  2572.     }    /* end if (l > 0) */
  2573.     DisposHandle(h);
  2574.     }
  2575. }
  2576.  
  2577. /*
  2578.  * Paste into the command window.
  2579.  */
  2580. cmd_paste (struct termw *termw)
  2581. {
  2582.     char *cp, *endp;
  2583.     char **h;
  2584.     long l, o;
  2585.     ScrapStuff *pss;
  2586.  
  2587.     pss = InfoScrap();
  2588.     if (my_scrapcount == pss->scrapCount) {
  2589.         /* if this is still the same scrap that we made */
  2590.     if (myclip_size > 0) {
  2591.         HLock((Handle) myclip_h);
  2592.         cp = *myclip_h;
  2593.         endp = cp + myclip_size;
  2594.         for (; cp < endp; cp++) {
  2595.         writecbc(*cp);
  2596.         if (*cp == CR)
  2597.             waitasec (termw);
  2598.         }
  2599.         HUnlock((Handle) myclip_h);
  2600.     } else {
  2601.         SysBeep(3);
  2602.     }
  2603.     } else {    /* we have to get the TEXT scrap from the clipboard */
  2604.     h = NewHandle(0);
  2605.     l = GetScrap(h, 'TEXT', &o);
  2606.     if (l <= 0) {
  2607.         SysBeep(3);
  2608.     } else {
  2609.         HLock((Handle) h);
  2610.         cp = *h;
  2611.         endp = cp + l;
  2612.         for (; cp < endp; cp++) {
  2613.             /* $$$ Should convert *cp to whatever ISO font we are typing */
  2614.         writecbc(*cp);
  2615.         if (*cp == CR)
  2616.             waitasec (termw);
  2617.         }
  2618.         HUnlock((Handle) h);
  2619.     }    /* end if (l > 0) */
  2620.     DisposHandle(h);
  2621.     }
  2622. }
  2623.  
  2624.  
  2625. /****************************************************************************/
  2626. /****************************************************************************/
  2627.  
  2628. #ifdef COMMENT
  2629. show_inval_rgn(w)
  2630. WindowPeek w;
  2631. {
  2632.     RgnHandle r = NewRgn();
  2633.  
  2634.     CopyRgn (w->updateRgn, r);
  2635.     OffsetRgn(r,            /* convert to local grafport coords */
  2636.           (((w->port).portBits).bounds).left,
  2637.           (((w->port).portBits).bounds).top);
  2638.     FillRgn(r, qd.gray);
  2639.     DisposeRgn(r);
  2640.     waitnoinput ();
  2641.     waitnoinput ();
  2642.     waitnoinput ();
  2643.     waitnoinput ();
  2644. }
  2645. #endif /* COMMENT */
  2646.  
  2647. /****************************************************************************/
  2648. /*
  2649.  * PWP: actually do all the scrolling and refreshing we have promised to
  2650.  * do.
  2651.  *
  2652.  * Method (and many var and fcn names) stolen from X11 xterm.
  2653.  */
  2654. /****************************************************************************/
  2655. void flushscroll (struct termw *termw)
  2656. {
  2657.     register int i, now;
  2658.     Rect r;            /* , opened_r   cannot be register */
  2659.     GrafPtr currWindow;        /* cannot be register */
  2660.     RgnHandle newupdateRgn;
  2661.     Rect *rp;
  2662.     int lin;
  2663.     int vtoplin, vbotlin, vleftcol, vrightcol;
  2664.     
  2665.     if (termw->scroll_amount == 0) {
  2666.         printerr ("flushscroll() called with no scroll to flush", 0);
  2667.         return;
  2668.     }
  2669.     
  2670.     /* should hide the cursor here if not already hidden */
  2671.     
  2672.     /* (PWP) if our selected region overlaps, but is not enclosed by the region
  2673.        we want to scroll, then remove it, because the region no longer contains
  2674.        what the user thought it did. */
  2675.     if (termw->have_selection && (termw->saved_tlin != toplin) && 
  2676.     (termw->saved_blin != botlin) && 
  2677.     ((termw->from_lin < termw->saved_tlin) || 
  2678.      (termw->to_lin > termw->saved_blin)) &&
  2679.         ((termw->to_lin > termw->saved_tlin)   || 
  2680.      (termw->from_lin < termw->saved_blin))) {
  2681.     termw->have_selection = FALSE;
  2682.     invert_text(termw, termw->from_lin, termw->from_col, termw->to_lin, 
  2683.             termw->to_col);
  2684.     }
  2685.     
  2686.     if (!termw->in_front) {
  2687.     /* if not in front, compensate update region for scrolling */
  2688.     GetPort (&currWindow);
  2689.     /* scroll the old updateRgn */
  2690.     OffsetRgn (((WindowPeek) currWindow)->updateRgn, 0, 
  2691.            -termw->lineheight);
  2692.     }
  2693.     
  2694.  
  2695.     /* 
  2696.      * Do the scrolling
  2697.      */
  2698.     makerect(termw,&r, termw->saved_tlin, 0,
  2699.          termw->saved_blin - termw->saved_tlin + 1, MAXCOL);
  2700.     newupdateRgn = NewRgn();
  2701.     
  2702.     if (termw->smoothscroll && termw->in_front) {
  2703.     int dir = 1;            /* direction */
  2704.     if (termw->scroll_amount < 0)
  2705.         dir = -1;
  2706.     for (i = 1; i <= termw->scroll_amount*termw->lineheight*dir; i += 1) {
  2707.         /* PWP: wait for a vertical reblank (in a sneaky way) */
  2708.         now = TickCount ();
  2709.         while (TickCount () == now)
  2710.         /* wait... */ ;
  2711.         ScrollRect (&r, 0, dir, newupdateRgn);
  2712.     }
  2713.     } else {
  2714.     ScrollRect (&r, 0, termw->scroll_amount * termw->lineheight, 
  2715.             newupdateRgn);
  2716.     }
  2717.  
  2718.     /*
  2719.      * NOTE: We don't add the newupdateRgn to the actual window update region,
  2720.      * but instead we just update all the lines that are in the region now.
  2721.      * This is faster, gives a smoother appearance to background windows, and
  2722.      * avoids an apparent bug in the Mac that causes multiplely scrolled
  2723.      * update regions to be incorrect.
  2724.      */
  2725.  
  2726.  
  2727.     termw->scroll_amount = 0;        /* we've done it now */
  2728.  
  2729.     /*
  2730.      * Find the intersection of what we just opened up and the visible portion
  2731.      * of the screen, and update all the lines in that rectangle.
  2732.      */
  2733.     rp = &(**(newupdateRgn)).rgnBBox;
  2734.  
  2735.     /* show the region to be updated -- only for debugging */
  2736.     /* FillRgn(newupdateRgn, qd.gray); */
  2737.     /* FillRect (rp, qd.gray); */
  2738.  
  2739.     /* Find the characters that bound this rectangle */
  2740.     recttocharpos (termw, rp, &vtoplin, &vleftcol, &vbotlin, &vrightcol);
  2741.  
  2742.     /* Make sure we pick up any extra refresh region */
  2743.     if (termw->refresh_amount < 0) {        /* scrolling forward (UP) */
  2744.     if (vtoplin > termw->saved_blin + termw->refresh_amount)
  2745.         vtoplin = termw->saved_blin + termw->refresh_amount;
  2746.     } else if (termw->refresh_amount > 0) {    /* scrolling backward (DOWN) */
  2747.     if (vbotlin < termw->saved_tlin + termw->refresh_amount - 1)
  2748.         vbotlin = termw->saved_tlin + termw->refresh_amount - 1;
  2749.     }
  2750.     
  2751.     /* bounds limit it to the actual screen area (again) */
  2752.     if (vtoplin < 0) vtoplin = 0;
  2753.     if (vbotlin > termw->screensize) vbotlin = termw->screensize;
  2754.  
  2755.     lin = termw->display_topline + vtoplin;
  2756.     for (i = vtoplin; i < vbotlin; i++) {
  2757.     makerect(termw, &r, i, vleftcol, 1, (vrightcol - vleftcol));
  2758.  
  2759.     /*
  2760.      * According to IM 1 pp 185, RectInRgn isn't always exact, so we might
  2761.      * try the more exact way if this isn't good enough.
  2762.      */
  2763.     if (RectInRgn(&r, newupdateRgn)) {
  2764.         draw_line_w_attrs(termw, lin, i, vleftcol, vrightcol, 0);
  2765.  
  2766.         /*
  2767.          * If we just drew the line that flushbuf thinks is pending,
  2768.          * say we have done so in order to avoid drawing that line twice.
  2769.          */
  2770.         if (i == termw->curlin)
  2771.         termw->out_maxcol = 0;
  2772.     }
  2773.     lin++;
  2774.     }
  2775.  
  2776.     DisposeRgn(newupdateRgn);
  2777.  
  2778.     termw->refresh_amount = 0;
  2779. }
  2780.  
  2781.  
  2782. /****************************************************************************/
  2783. /*
  2784.  * (UoR)
  2785.  *
  2786.  * Scroll lines within the scroll region upwards from line tlin
  2787.  * to line blin (lines are assumed to be in the region)
  2788.  *
  2789.  * (PWP) scroll_screen is the combination of scroll_up and scroll_down.
  2790.  *       dir is the number of lines to scroll, <0 if up, >0 if down.
  2791.  *     (actually, right now only -1 and 1 are handled.)
  2792.  */
  2793. /****************************************************************************/
  2794. void scroll_screen (termw, tlin, blin, delta)
  2795. /* these are in scr[][] cordinates */
  2796.     struct termw *termw;
  2797.     register int tlin;
  2798.     register int blin;
  2799.     register int delta;
  2800. {
  2801.     register int i, now;
  2802.     char *savedline, *savedattr;  /* temporary to hold screen line pointer */
  2803.     unsigned char savedlattr;
  2804.     
  2805.     /*
  2806.      * flush out any pending characters.
  2807.      *
  2808.      * $$$ I bet this is the piece of bogus code that was causing me all the
  2809.      * trouble.  We NEED to do this, or else keep track of where out_mincol and
  2810.      * out_maxcol were when we set up the scroll for the first time, so that
  2811.      * we don't mistakenly miss drawing the pending stuff.
  2812.      */
  2813.     if (!termw->scroll_amount && termw->out_maxcol) 
  2814.     flushbuf(termw);
  2815.  
  2816.     /*
  2817.      * See if we are scrolling something different and have to flush
  2818.      * our pending scroll.
  2819.      * We do if asked to scroll something different than the current
  2820.      * scrolling rgn, or if we are changing direction, or if we have 
  2821.      * already collected an entire scrolling region worth of scroll to do.
  2822.      */
  2823.     if (termw->scroll_amount) {
  2824.     i = termw->scroll_amount + delta;
  2825.     if (i < 0) i = -i;    /* set i to ABS( old scroll plus new scroll ) */
  2826.     if (termw->smoothscroll || 
  2827.         (tlin != termw->saved_tlin) || 
  2828.         (blin != termw->saved_blin) || 
  2829.         ((termw->scroll_amount > 0) && (delta < 0)) ||
  2830.         ((termw->scroll_amount < 0) && (delta > 0)) ||
  2831.         (i >= (termw->saved_blin - termw->saved_tlin))) 
  2832.     {
  2833.         flushscroll(termw);
  2834.     }
  2835.     }
  2836.  
  2837.     /*
  2838.      * Save up how much to scroll and where for later...
  2839.      */
  2840.     termw->saved_tlin = tlin;
  2841.     termw->saved_blin = blin;
  2842.     termw->scroll_amount += delta;
  2843.     /*
  2844.      * Should really set termw->refresh_amount to 0, then add to it 
  2845.      * when we "draw" characters onto lines, but this is safe.
  2846.      */
  2847.     termw->refresh_amount += delta;
  2848.     
  2849.     /* printerr("termw->scroll_amount now ", scroll_amount); */
  2850.  
  2851.     if (delta < 0)        /* if scrolling UP (forwards) */
  2852.     {
  2853.     /* adjust the internal character buffers */
  2854.     if ((tlin == toplin) && (blin == botlin)) { /* if whole screen */
  2855.         termw->display_totlines -= delta; /* remember delta is negitive */
  2856.         if (termw->display_totlines > MAX_SCREENSIZE)
  2857.         termw->display_totlines = MAX_SCREENSIZE; /* bounds */
  2858.         /*top of saved buffer*/
  2859.             tlin = termw->screensize - termw->display_totlines;
  2860.     }
  2861.     for (now = 0; now < -delta; now++) {
  2862.          savedline = termw->scr[tlin];
  2863.         savedattr = termw->scr_attrs[tlin];
  2864.         savedlattr = termw->line_attrs[tlin];
  2865.         for (i = tlin+1; i <= blin; i++) {
  2866.             termw->scr[i-1] = termw->scr[i];
  2867.             termw->scr_attrs[i-1] = termw->scr_attrs[i];
  2868.         termw->line_attrs[i-1] = termw->line_attrs[i];
  2869.         }
  2870.         termw->scr[blin] = savedline;
  2871.         termw->scr_attrs[blin] = savedattr;
  2872.         termw->line_attrs[blin] = savedlattr;
  2873.  
  2874.         zeroline(termw, blin, 1);        /* clear the line */
  2875.     }
  2876.  
  2877.     /* adjust selection */
  2878.     if (termw->have_selection && (termw->from_lin >= tlin) && 
  2879.         (termw->to_lin <= blin)) 
  2880.        {
  2881.         termw->from_lin += delta;
  2882.         if (termw->from_lin < termw->screensize - MAX_SCREENSIZE)
  2883.             termw->from_lin = termw->screensize - MAX_SCREENSIZE;
  2884.         termw->to_lin += delta;
  2885.         if (termw->to_lin < termw->screensize - MAX_SCREENSIZE)
  2886.             termw->to_lin = termw->screensize - MAX_SCREENSIZE;
  2887.     }
  2888.     }
  2889.     else            /* else scrolling DOWN (reverse scroll) */
  2890.     {
  2891.         /* adjust the internal buffers */
  2892.     for (now = 0; now < delta; now++) {
  2893.         savedline = termw->scr[blin];
  2894.         savedattr = termw->scr_attrs[blin];
  2895.         savedlattr = termw->line_attrs[blin];
  2896.         for (i = blin-1; i >= tlin; i--) {
  2897.             termw->scr[i+1] = termw->scr[i];
  2898.             termw->scr_attrs[i+1] = termw->scr_attrs[i];
  2899.         termw->line_attrs[i+1] = termw->line_attrs[i];
  2900.         }
  2901.         termw->scr[tlin] = savedline;
  2902.         termw->scr_attrs[tlin] = savedattr;
  2903.         termw->line_attrs[tlin] = savedlattr;
  2904.  
  2905.         zeroline(termw, tlin, 1);
  2906.     }
  2907.     
  2908.     /* adjust selection */
  2909.     if (termw->have_selection && (termw->from_lin >= tlin) && 
  2910.         (termw->to_lin <= blin)) 
  2911.     {
  2912.         termw->from_lin += delta;
  2913.         if (termw->from_lin > botlin) termw->from_lin = botlin;
  2914.         termw->to_lin += delta;
  2915.         if (termw->to_lin > botlin) termw->to_lin = botlin;
  2916.     }
  2917.     }
  2918.  
  2919.     /*
  2920.      * but if we are smooth (slow) scrolling and in front, do the scroll now.
  2921.      * must do this after adjusting internal buffers, so that the refresh
  2922.      * lines don't get confused.
  2923.      */
  2924.     if (termw->smoothscroll && termw->in_front)
  2925.         flushscroll(termw);
  2926. }                /* scroll_up */
  2927.  
  2928. /****************************************************************************/
  2929. /* redraw the terminal screen (we got a redraw event) */
  2930. /****************************************************************************/
  2931. term_redraw (struct termw *termw)
  2932. {
  2933.     int i, lin;
  2934.     int vtoplin, vbotlin, vleftcol, vrightcol;
  2935.     Rect r, *rp;
  2936.     GrafPtr savePort;
  2937.     
  2938.     GetPort (&savePort);    /* there just has to be a better way */
  2939.     SetPort (termw->window);
  2940.  
  2941.     if (termw->screeninvert) {
  2942.     BackPat(qd.black);
  2943.     PenPat(qd.white);
  2944.     } else {
  2945.     BackPat(qd.white);
  2946.     PenPat(qd.black);
  2947.     }
  2948.  
  2949.     if (termw->scroll_amount)
  2950.     flushscroll(termw);
  2951.  
  2952. #ifdef COMMENT
  2953.     r = terminalWindow->portRect;    /* copy the window size */
  2954.     /* r.right -= 15;    */        /* subtract control */
  2955.     /* PWP: clear the screen first */
  2956.     /* makerect(termw,&r, 0, 0, termw->screensize, MAXCOL); */
  2957.     /* EraseRect (&r); */
  2958. #endif /* COMMENT */
  2959.  
  2960.     /* See if the scroll bar and grow box need to be updated */
  2961.     r = termw->window->portRect;    /* copy of the window size */
  2962.     /* r.left = r.right - 16; */
  2963.     r.left = rightMARGIN;
  2964.     if (RectInRgn (&r, termw->window->visRgn))
  2965.     {
  2966.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  2967.     EraseRect (&r);
  2968.     /* don't add to invalid while redrawing invalid */
  2969.     draw_grow_and_erase_line(termw, 0);
  2970.     DrawControls (termw->window);
  2971.     }
  2972.  
  2973.     /* Update area above first line */
  2974.     r = termw->window->portRect;    /* copy of the window size */
  2975.     r.bottom = r.top + TOPMARGIN;
  2976.     r.right -= 16;
  2977.     if (RectInRgn (&r, termw->window->visRgn))
  2978.     EraseRect (&r);
  2979.  
  2980.     /* Update area below last line */
  2981.     r = termw->window->portRect;    /* copy of the window size */
  2982.     r.top = termw->bottommargin - 1;
  2983.     r.right -= 16;
  2984.     if (RectInRgn (&r, termw->window->visRgn))
  2985.     EraseRect (&r);
  2986.  
  2987.     /* Update area to the left of first column */
  2988.     r = termw->window->portRect;    /* copy of the window size */
  2989.     r.top = r.top + TOPMARGIN;
  2990.     r.bottom = termw->bottommargin;
  2991.     r.right = LEFTMARGIN;
  2992.     if (RectInRgn (&r, termw->window->visRgn))
  2993.     EraseRect (&r);
  2994.  
  2995.     
  2996.     /* update_vscroll(termw); */
  2997.     /* SetCtlValue (termw->t_vscroll, GetCtlValue (t_vscroll)); */
  2998.  
  2999. #ifdef COMMENT
  3000.     lin = termw->display_topline;
  3001.     for (i = 0; i < termw->screensize; i++) {
  3002.         makerect(termw,&r, i, 0, 1, MAXCOL);
  3003.     if (RectInRgn (&r, termw->window->visRgn))
  3004.         draw_line_w_attrs(termw, lin, i, 0, MAXCOL, 1);
  3005.     lin++;
  3006.     }
  3007. #endif
  3008.  
  3009.     rp = &(**(termw->window->visRgn)).rgnBBox;
  3010.  
  3011.     /* Find the characters that bound this rectangle */
  3012.     recttocharpos(termw, rp, &vtoplin, &vleftcol, &vbotlin, &vrightcol);
  3013.  
  3014. #ifdef COMMENT
  3015.     debug(F101,"term_redraw bounds vtoplin","",vtoplin);
  3016.     debug(F101,"term_redraw bounds vbotlin","",vbotlin);
  3017.     debug(F101,"term_redraw bounds vleftcol","",vleftcol);
  3018.     debug(F101,"term_redraw bounds vrightcol","",vrightcol);
  3019. #endif
  3020.  
  3021.     lin = termw->display_topline + vtoplin;
  3022.     for (i = vtoplin; i < vbotlin; i++) {
  3023.     makerect(termw, &r, i, 0, 1, MAXCOL);
  3024.     if (RectInRgn (&r, termw->window->visRgn))
  3025.         draw_line_w_attrs(termw, lin, i, vleftcol, vrightcol, 1);
  3026.     lin++;
  3027.     }
  3028.     
  3029.     
  3030.     if (termw->have_selection)
  3031.         invert_text(termw,
  3032.             termw->from_lin,
  3033.             termw->from_col,
  3034.             termw->to_lin,
  3035.             termw->to_col);
  3036.  
  3037.     /* (UoR) only if cursor is showing */
  3038.     if (termw->cur_drawn && termw->cursor_invert) {
  3039.     termw->cursor_invert = FALSE;    /* (UoR) make sure we draw it */
  3040.     cursor_draw(termw);        /* redraw cursor */
  3041.     termw->last_flash = TickCount (); /* (UoR) reset timer */
  3042.     }
  3043.  
  3044.     SetPort (savePort);        /* there just has to be a better way */
  3045. }                /* term_redraw */
  3046.  
  3047. draw_grow_and_erase_line (struct termw *termw, int invalidate_it)
  3048. {
  3049.     Rect r;
  3050.  
  3051.     DrawGrowIcon (termw->window);
  3052.     /* erase the bottom scroll line (but only if inverted screen) */
  3053.     if (!termw->screeninvert) {
  3054.     PenMode(patBic);
  3055.     MoveTo(0, (termw->window->portRect).bottom - 15);
  3056.     LineTo((termw->window->portRect).right - 15,
  3057.             (termw->window->portRect).bottom - 15);
  3058.     PenMode(patCopy);
  3059.     }
  3060.     
  3061.     if (invalidate_it) {
  3062.     r.top = (termw->window->portRect).bottom - 16;
  3063.     r.bottom = (termw->window->portRect).bottom - 14;
  3064.     r.left = 0;
  3065.     r.right = (termw->window->portRect).right - 16;
  3066.     InvalRect(&r);
  3067.     }
  3068. }
  3069.  
  3070. term_activate (struct termw *termw, int mod)
  3071. {
  3072.     GrafPtr savePort;
  3073.     
  3074.     GetPort (&savePort);
  3075.     SetPort (termw->window);
  3076.  
  3077.     cursor_erase (termw);        /* remove cursor from screen */
  3078.     termw->in_front = mod & activeFlag;
  3079.     if (termw->in_front) {
  3080.     UpdateOptKey(1);
  3081.     DisableItem(menus[EDIT_MENU], UNDO_EDIT);
  3082.     DisableItem(menus[EDIT_MENU], CLEAR_EDIT);
  3083.     } else {
  3084.     UpdateOptKey(0);
  3085.     EnableItem(menus[EDIT_MENU], UNDO_EDIT);
  3086.     EnableItem(menus[EDIT_MENU], CLEAR_EDIT);
  3087.     }
  3088.     /* these do the right thing for background too */
  3089.     update_vscroll (termw);
  3090.     draw_grow_and_erase_line(termw, 1);
  3091.     cursor_draw(termw);
  3092.  
  3093.     SetPort (savePort);
  3094. }
  3095.  
  3096. /*
  3097.  * This CAN be called external to inpchars(), so save and restore the
  3098.  * GrafPort just in case.
  3099.  */
  3100. set_term_invert (struct termw *termw, int new_inv)
  3101. {
  3102.     GrafPtr savePort;
  3103.     
  3104.     GetPort (&savePort);    /* there just has to be a better way */
  3105.     SetPort (termw->window);
  3106.  
  3107.     if (new_inv == termw->screeninvert)
  3108.         return;
  3109.     
  3110.     if (new_inv) {
  3111.     BackPat (qd.black);    /* (UoR) use black background */
  3112.     PenPat(qd.white);
  3113.     termw->screeninvert = TRUE;
  3114.     } else {
  3115.     BackPat (qd.white);
  3116.     PenPat(qd.black);
  3117.     termw->screeninvert = FALSE;
  3118.     }
  3119.     InvalRect(&termw->window->portRect);/* invalidate whole window rectangle */
  3120.     SetPort (savePort);        /* there just has to be a better way */
  3121. }
  3122.  
  3123. /****************************************************************************/
  3124. /* sizevscroll - called when window is created and after a window grow */
  3125. /*                      sequence to resize the scroll window's bars. */
  3126. /****************************************************************************/
  3127. void sizevscroll (struct termw *termw)
  3128. {
  3129.     register Rect *r;
  3130.  
  3131.     if (!termw)
  3132.     DebugStr("\psizevscroll called with termw == NULL");
  3133.  
  3134.     r = &termw->window->portRect;/* window size */
  3135.     HideControl (termw->t_vscroll);
  3136.  
  3137.     MoveControl (termw->t_vscroll, r->right - 15, r->top - 1);
  3138.     SizeControl (termw->t_vscroll, 16, r->bottom - r->top - 13);
  3139.  
  3140.     SetCtlMin (termw->t_vscroll, 0);
  3141.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  3142.     update_vscroll(termw);
  3143.     ShowControl (termw->t_vscroll);
  3144. }
  3145.  
  3146. /****************************************************************************/
  3147. /* initalize the terminal emulator. */
  3148. /****************************************************************************/
  3149. init_term (struct termw *termw)
  3150. {
  3151.     register int i, j;
  3152.     register char *scp, *acp;
  3153.     char *scr_cp, *attr_cp;
  3154.     GrafPtr savePort;
  3155.     
  3156.     GetPort (&savePort);    /* there just has to be a better way */
  3157.     SetPort (termw->window);
  3158.    
  3159.     termw->topmargin = TOPMARGIN;    /* Edges of adjustable window */
  3160.     termw->bottommargin = bottomMARGIN;
  3161.     
  3162.     if ((scr_cp = (char *)NewPtr(((long)(MAXCOL+1) * (long) MAX_SCREENSIZE)))
  3163.     == NIL)
  3164.       macfatal("Could not allocate screen buffer", 0);
  3165.     
  3166.     if ((attr_cp = (char *)NewPtr(((long)(MAXCOL+1) * (long) MAX_SCREENSIZE)))
  3167.     == NIL)
  3168.       macfatal("Could not allocate screen attribute buffer", 0);
  3169.     
  3170.     if ((termw->real_scr = (ucharptr *) NewPtr ((long)(MAX_SCREENSIZE)
  3171.                      * (long) sizeof(ucharptr))) == NIL)
  3172.     macfatal("Could not allocate screen buffer", 0);
  3173.     
  3174.     if ((termw->real_attrs = (ucharptr *) NewPtr ((long)(MAX_SCREENSIZE)
  3175.                        * (long) sizeof(ucharptr))) == NIL)
  3176.     macfatal("Could not allocate screen buffer", 0);
  3177.  
  3178.     if ((termw->real_ln_attrs
  3179.      = (unsigned char *) NewPtr ((long)(MAX_SCREENSIZE)
  3180.                      * (long) sizeof(unsigned char))) == NIL)
  3181.     macfatal("Could not allocate screen buffer", 0);
  3182.  
  3183.     for (i = 0; i < MAX_SCREENSIZE; i++) {
  3184.     /* divvy up screen buffer */
  3185.         termw->real_scr[i] = scr_cp + (i * (MAXCOL+1));
  3186.     /* divvy up screen attribute buf */
  3187.         termw->real_attrs[i] = attr_cp + (i * (MAXCOL+1));
  3188.  
  3189.     scp = termw->real_scr[i];
  3190.     acp = termw->real_attrs[i];
  3191.     j = MAXCOL;
  3192.     do {            /* put normal spaces in all columns */
  3193.         *scp++ = ' ';
  3194.         *acp++ = 0;
  3195.     } while (--j > 0);
  3196.     *scp = ' ';        /* Terminate the lines as strings */
  3197.     *acp = 0;        /* Terminate the attrs as strings */
  3198.     termw->real_ln_attrs[i] = VT_SNGL;    /* reset line attributes */
  3199.     }
  3200.     
  3201.     termw->scr = &termw->real_scr[MAX_SCREENSIZE - termw->screensize];
  3202.     if (termw->scr[0] == NIL)
  3203.     macfatal("init_term: scr assignment botched for [0]", 0);
  3204.     if (termw->scr[termw->screensize-1] == NIL)
  3205.     macfatal("\
  3206. init_term: scr assignment botched for [termw->screensize-1]", 0);
  3207.  
  3208.     termw->scr_attrs = &termw->real_attrs[MAX_SCREENSIZE - termw->screensize];
  3209.     if (termw->scr_attrs[0] == NIL)
  3210.     macfatal("init_term: scr assignment botched for [0]", 0);
  3211.     if (termw->scr_attrs[termw->screensize-1] == NIL)
  3212.     macfatal("\
  3213. init_term: scr assignment botched for [termw->screensize-1]", 0);
  3214.     
  3215.     termw->line_attrs = &termw->real_ln_attrs[MAX_SCREENSIZE
  3216.                           - termw->screensize];
  3217.  
  3218.     termw->scrtop = toplin;        /* Scrolling region equals all */
  3219.     termw->scrbot = botlin;
  3220.     
  3221.     termw->scroll_amount = 0;        /* no pending scroll */
  3222.     termw->refresh_amount = 0;        /* no pending refresh */
  3223.     termw->saved_tlin = 0;
  3224.     termw->saved_blin = 0;
  3225.     
  3226.     termw->display_topline = toplin;    /* init display w/elevator at bottom */
  3227.     termw->display_totlines = termw->screensize;
  3228.     makerect(termw,&termw->ScreenRect, 0, 0, termw->screensize, MAXCOL);
  3229.     /* (UoR) full screen rectangle */
  3230.     
  3231.     SizeWindow(termw->window,
  3232.         rightMARGIN + 1 + 16,     /* add extra to side for asthetics */
  3233.     bottomMARGIN + TOPMARGIN,     /* add extra to bottom for asthetics */
  3234.     FALSE);
  3235.     /* PWP: make the window match it's real size */
  3236.  
  3237.     termw->t_vscroll = GetNewControl (RCMDVSCROLL, termw->window);
  3238.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  3239.     sizevscroll(termw);
  3240.  
  3241.     InitKeyStuff();        /* find the original KCHR keymaps */
  3242.  
  3243. #ifdef COMMENT
  3244.     draw_grow_and_erase_line(0);    /* it's new so don't invalidate it */
  3245. #endif
  3246.  
  3247.     /* ClipRect(&termw->ScreenRect); */
  3248.  
  3249.     SetPort (savePort);        /* there just has to be a better way */
  3250. }                /* init_term */
  3251.  
  3252. /****************************************************************************/
  3253. /* grow_term_to(termw, size) -- change the size of the terminal window to size.
  3254.    this is called by growterm() (see below) and the terminal settings dialog
  3255.    handler (termsetdialog()).
  3256. /****************************************************************************/
  3257. grow_term_to (struct termw *termw, int size)
  3258. {
  3259.     GrafPtr savePort;
  3260.  
  3261.     GetPort (&savePort);
  3262.     SetPort (termw->window);
  3263.  
  3264.     if ((size < 1) || (size > MAX_SCREENSIZE))
  3265.        size = 24;    /* the default case */
  3266.     
  3267.     if (size > termw->display_totlines) { 
  3268.     /* 
  3269.      * if getting bigger than we were
  3270.      * We would zero out lines from (termw->screensize-size) to 
  3271.      * (termw->screensize-display_totlines),
  3272.      * but these were already zeroed when the original screen was inited.
  3273.      */
  3274.     termw->display_totlines = size;
  3275.     }
  3276.     
  3277.     /* $$$ Make sure to scroll screen to what will be the new bottom here */
  3278.  
  3279.     /* adjust cursor row to match stretch */
  3280.     termw->curlin += size - termw->screensize;
  3281.     if (termw->curlin < 0)
  3282.     termw->curlin = 0;
  3283.     if (termw->curlin > size-1)
  3284.     termw->curlin = size-1;
  3285.     
  3286.     termw->screensize = size;
  3287.     if (termw->screensize > MAX_SCREENSIZE)
  3288.         termw->screensize = MAX_SCREENSIZE;        /* bounds check */
  3289.  
  3290.     termw->scr = &termw->real_scr[MAX_SCREENSIZE - termw->screensize];
  3291.     termw->scr_attrs = &termw->real_attrs[MAX_SCREENSIZE - termw->screensize];
  3292.     termw->line_attrs = &termw->real_ln_attrs[MAX_SCREENSIZE
  3293.                           - termw->screensize];
  3294.    
  3295.     termw->bottommargin = bottomMARGIN;    /* this changes */
  3296.     
  3297.     termw->scrtop = toplin;        /* Scrolling region equals all */
  3298.     termw->scrbot = botlin;
  3299.     termw->display_topline = 0;    /* re-init display w/elevator at bottom */
  3300.     makerect(termw,&termw->ScreenRect, 0, 0, termw->screensize, MAXCOL);
  3301.     /* (UoR) full screen rectangle */
  3302.     
  3303.     SizeWindow(termw->window,
  3304.         rightMARGIN + 1 + 16,     /* add extra to side for asthetics */
  3305.     bottomMARGIN + TOPMARGIN,     /* add extra to bottom for asthetics */
  3306.     FALSE);
  3307.     /* PWP: make the window match it's real size */
  3308.     termw->scroll_drawn = -1;        /* mark scroll bar invalid */
  3309.     sizevscroll(termw);    /* size the scroll bars */
  3310.  
  3311.     /* ClipRect(&termw->ScreenRect); */
  3312.  
  3313.     /* invalidate whole window rectangle */
  3314.     InvalRect (&termw->window->portRect);
  3315.  
  3316.     SetPort (savePort);
  3317. }                /* grow_term_to */
  3318.  
  3319. /****************************************************************************/
  3320. /* 
  3321.  * growterm() -- called when we get a mouse-down in the lower right corner grow
  3322.  * box.
  3323.  * Probably all right not to save the grafport, but we do anyway just to be
  3324.  * double extra safe.
  3325.  */
  3326. /****************************************************************************/
  3327. growterm (struct termw *termw, Point *p)
  3328. {
  3329.     long gr;
  3330.     int height;
  3331.     int width;
  3332.     int size;
  3333.     Rect growRect;
  3334.     GrafPtr savePort;
  3335.     
  3336.     GetPort (&savePort);    /* there just has to be a better way */
  3337.     SetPort (termw->window);
  3338.  
  3339.     growRect = qd.screenBits.bounds;
  3340.     growRect.top = 50;        /* minimal horizontal size */
  3341.     growRect.left = rightMARGIN + 18;    /* minimal vertical size */
  3342.     growRect.right = rightMARGIN + 18;    /* minimal vertical size */
  3343.  
  3344.     gr = GrowWindow (termw->window, *p, &growRect);
  3345.  
  3346.     if (gr == 0)
  3347.     return;
  3348.     height = HiWord (gr);
  3349.     width = LoWord (gr);
  3350.  
  3351.     size = (height - (2 * TOPMARGIN)) / termw->lineheight;
  3352.     if (size > MAX_SCREENSIZE)
  3353.         termw->screensize = MAX_SCREENSIZE;        /* bounds check */
  3354.     if (size < 1)
  3355.         size = 1;
  3356.  
  3357.     grow_term_to(termw, size);
  3358.  
  3359.     SetPort (savePort);        /* there just has to be a better way */
  3360. }                /* growterm */
  3361.  
  3362. /****************************************************************************/
  3363. get_term_pos(struct termw *termw, int *top_p, int *left_p)
  3364. {
  3365.     Point mypoint;
  3366.     GrafPtr savePort;
  3367.     
  3368.     GetPort (&savePort);    /* there just has to be a better way */
  3369.     SetPort (termw->window);
  3370.  
  3371.     mypoint.v = termw->window->portRect.top;
  3372.     mypoint.h = termw->window->portRect.left;
  3373.     LocalToGlobal(&mypoint);
  3374.     
  3375.     if (top_p)
  3376.     *top_p = mypoint.v;
  3377.     if (top_p)
  3378.     *left_p = mypoint.h;
  3379.     
  3380.     SetPort (savePort);        /* there just has to be a better way */
  3381. }
  3382.  
  3383. set_term_pos(struct termw *termw, int top, int left)
  3384. {
  3385.     MoveWindow(termw->window, left, top, TRUE);
  3386. }
  3387.  
  3388. /*
  3389.  * Junk so Emacs will set local variables to be compatible with Mac/MPW.
  3390.  * Should be at end of file.
  3391.  * This module was apparently formatted with tabs = 8
  3392.  * 
  3393.  * Local Variables:
  3394.  * tab-width: 8
  3395.  * End:
  3396.  */
  3397.